1.sys文件夾介紹(掌握)
??下面函數(shù)都是以sys_開頭,定義在sys.c中。正點原子函數(shù)現(xiàn)階段命名規(guī)則如果是在led.c中,則以led_開頭。在F7/H7系列中會存在Cache配置函數(shù),I-Cache中存儲指令,D-Cache中存儲數(shù)據(jù)。
2.deley文件夾介紹(掌握)
2.1deley文件夾函數(shù)簡介
2.2SysTick工作原理
??SysTick,即系統(tǒng)滴答定時器,包含在M3/4/7內(nèi)核里面,核心是一個24位的遞減計數(shù)器(最大計數(shù)值為224=16777216)。當計數(shù)器減至0時,證明延時成功,則讓COUNTFLAG置1,并將重裝載寄存器中的值賦給計數(shù)器,重裝載值可以自己設(shè)置,取值范圍是從0開始0~16777215。
??每次VAL到0時,VAL自動從LOAD重載,開始新一輪遞減計數(shù)。
2.3SysTick寄存器介紹
??SysTick控制及狀態(tài)寄存器(CTRL)(摘自:Cortex M3權(quán)威指南(中文).pdf)。其中,CLKSOURCE并不是時鐘源選擇位,而是配置分頻系數(shù)。
SysTick重裝載數(shù)值寄存器(LOAD)(摘自:Cortex M3權(quán)威指南(中文).pdf),LOAD中的值會重裝載到VAL寄存器中。
SysTick當前數(shù)值寄存器(VAL) (摘自:Cortex M3權(quán)威指南(中文).pdf)
2.4delay_init()函數(shù)(F1)
??形參sysclk為系統(tǒng)時鐘,單位是M,比如在F1系列中系統(tǒng)時鐘為72MHz,則填入72。
??下列代碼第一行是設(shè)置系統(tǒng)滴答定時器的狀態(tài)控制寄存器為0,在進行dellay_init()
函數(shù)之前可能會調(diào)用HAL庫的初始化函數(shù),可以將系統(tǒng)滴答定時器的中斷以及其他設(shè)置配置好,這里需要按照我們自己的意愿來設(shè)置,所以需要將HAL庫設(shè)置的清0,不會干擾后面的配置;第二行是調(diào)用HAL庫的函數(shù)來選擇系統(tǒng)滴答定時器時鐘源分頻系數(shù),這里選擇8分頻,也就是將CTRL寄存器的位CLKSOURCE置0;第三行是定義全局變量,作為1us時基的來源,如果系統(tǒng)滴答定時器的計數(shù)頻率為1MHz,1秒鐘計數(shù)1000 000次,計數(shù)一次用1/1000 000次,F(xiàn)1系列的系統(tǒng)時鐘為72Mhz,系統(tǒng)滴答定時器進行8分頻,系統(tǒng)滴答定時器真正計數(shù)頻率為9Mhz,用sysclk除以8得到9Mhz,得到1us需要計數(shù)多少次。1/1000 000s=1us=g_fac_us ×1/9000 000,其中g_fac_us 為達到1us需要計數(shù)的次數(shù)。
void delay_init(uint16_t sysclk)
{
SysTick->CTRL = 0;
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
g_fac_us = sysclk / 8;
}
2.5delay_us()函數(shù)(F1)
??在9MHz的計數(shù)頻率上得到1us,需要進行計數(shù)9次,其中g_fac_us為9,使用變量temp來判斷滴答定時器是否在工作,位16是判斷計數(shù)是否完成,如果計數(shù)未完成則為0。
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick->LOAD = nus * g_fac_us; /* 時間加載 */
SysTick->VAL = 0x00; /* 清空計數(shù)器 */
SysTick->CTRL |= 1 << 0 ; /* 開始倒數(shù) */
do
{
temp = SysTick->CTRL;
} while ((temp & 0x01) && !(temp & (1 << 16))); /* CTRL.ENABLE位必須為1, 并等待時間到達 */
SysTick->CTRL &= ~(1 << 0) ; /* 關(guān)閉SYSTICK */
SysTick->VAL = 0X00; /* 清空計數(shù)器 */
}
2.6delay_ms()函數(shù)(F1)
??毫秒延時函數(shù)是利用us延時函數(shù)來實現(xiàn)的,那么就需要知道微秒延時函數(shù)的,所能延時的最大us數(shù),F(xiàn)1系統(tǒng)時鐘為72Mhz,經(jīng)過8分頻得到滴答定時器時鐘9Mhz計數(shù)頻率,計一個數(shù)為1/9000 000,可以計數(shù)224,則最大為1/9000 000 ×224≈1.864s,這是沒有考慮超頻,如果超頻到128Mhz,經(jīng)過8分頻為16Mhz,1/16000 000×224≈1.048576s。那么如果延時需要超過1ms,則可以調(diào)用多次delay_us()
函數(shù),如果不超過1ms,可以直接使用delay_us()
函數(shù)。
??代碼第一行首先對1000取整數(shù),將整數(shù)部分賦值給repeat 用于1s延時,小數(shù)部分賦值給remain用于小于1s的延時,用remain乘以1000是因為ms到us是相差1000倍。。
void delay_ms(uint16_t nms)
{
uint32_t repeat = nms / 1000; /* 這里用1000,是考慮到可能有超頻應(yīng)用,
* 比如128Mhz的時候, delay_us最大只能延時1048576us
*/
uint32_t remain = nms % 1000;
while (repeat)
{
delay_us(1000 * 1000); /* 利用delay_us 實現(xiàn) 1000ms 延時 */
repeat--;
}
if (remain)
{
delay_us(remain * 1000); /* 利用delay_us, 把尾數(shù)延時(remain ms)給做了 */
}
}
3.usart文件夾介紹(掌握)
3.1printf函數(shù)輸出流程
??如果要使用printf()
函數(shù),必須包含stdio.h頭文件,用工使用printf()
函數(shù),然后自動調(diào)用C標準庫鐘內(nèi)容,最終會調(diào)用fputc()
函數(shù),此函數(shù)與硬件相關(guān),通過屏幕或者串口來輸出內(nèi)容。
3.2printf的使用
- printf(“字符串\r\n”);使用\r\n實現(xiàn)換行,有些操作系統(tǒng)鐘只用\n即可,為了兼容不同的操作系統(tǒng)推薦使用\r\n來實現(xiàn)換行。
printf("Hello World!\r\n");
- printf(“輸出控制符”,輸出參數(shù));%d是輸出十進制數(shù)。
uint32_t temp = 10;
printf("%d\r\n", temp); /* %d是輸出控制符,temp是輸出參數(shù) */
- printf(“輸出控制符1輸出控制符2…”,輸出參數(shù)1,輸出參數(shù)2,…);%x以十六進制形式輸出,則輸出5A。
uint32_t temp1 = 5;
uint32_t temp2 = 10;
printf("%d%x\r\n", temp1,temp2);
- printf(“非輸出控制符 輸出控制符 非輸出控制符”,輸出參數(shù));
uint32_t temp = 10;
printf("temp= %d 收到over\r\n", temp);
- 如何輸出%、\和雙引號
printf("%% \r\n");
printf("\\\r\n");
printf("\"\"\r\n");
3.2.1常用輸出控制符表
3.2.2常用轉(zhuǎn)義字符表
3.3printf函數(shù)支持
- 避免使用半主機模式:兩種方法:微庫法、代碼法
- 實現(xiàn)
fputc
函數(shù)實現(xiàn)單個字符輸出
3.3.1半主機模式簡介
??用于 ARM 目標的一種機制,可將來自應(yīng)用程序代碼的輸入/輸出請求傳送至運行調(diào)試器的主機。簡單說,就是通過仿真器實現(xiàn)開發(fā)板在電腦上的輸入和輸出,一般我們不使用半主機模式。具體半主機模式的介紹可以查看參考鏈接。
3.3.2微庫法
??在魔術(shù)棒->Target選項卡,勾選【Use Micro LIB】,即可避免半主機模式。
3.3.3代碼法
??1個預處理、 2個定義、3個函數(shù)。
1.#pragma import(__use_no_semihosting),確保不從C庫中使用半主機函數(shù);
2.定義:__FILE結(jié)構(gòu)體,避免HAL庫某些情況下報錯;
3.定義: FILE __stdout,避免編譯報錯;
4.實現(xiàn):_ttywrch、_sys_exit和_sys_command_string等三個函數(shù)。
AC5和AC6不使用半主機模式稍有差異,詳見源碼
3.3.4微庫法VS代碼法
??推薦使用代碼法,正點原子源碼已做好。
/******************************************************************************************/
/* 加入以下代碼, 支持printf函數(shù), 而不需要選擇use MicroLIB */
#if 1
#if (__ARMCC_VERSION >= 6010050) /* 使用AC6編譯器時 */
__asm(".global __use_no_semihosting\n\t"); /* 聲明不使用半主機模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要聲明main函數(shù)為無參數(shù)格式,否則部分例程可能出現(xiàn)半主機模式 */
#else
/* 使用AC5編譯器時, 要在這里定義__FILE 和 不使用半主機模式 */
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
#endif
/* 不使用半主機模式,至少需要重定義_ttywrch\_sys_exit\_sys_command_string函數(shù),以同時兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
ch = ch;
return ch;
}
/* 定義_sys_exit()以避免使用半主機模式 */
void _sys_exit(int x)
{
x = x;
}
char *_sys_command_string(char *cmd, int len)
{
return NULL;
}
/* FILE 在 stdio.h里面定義. */
FILE __stdout;
/* MDK下需要重定義fputc函數(shù), printf函數(shù)最終會通過調(diào)用fputc輸出字符串到串口 */
int fputc(int ch, FILE *f)
{
while ((USART_UX->SR & 0X40) == 0); /* 等待上一個字符發(fā)送完成 */
USART_UX->DR = (uint8_t)ch; /* 將要發(fā)送的字符 ch 寫入到DR寄存器 */
return ch;
}
#endif
3.3.5實現(xiàn)fputc函數(shù)
??在fputc
函數(shù)中,第一行等待上一個字符發(fā)送完成,也就是檢查串口狀態(tài)寄存器SR的位6是否為1,為1則發(fā)送成功;第二行是將要發(fā)送的字符寫入到串口的數(shù)據(jù)寄存器DR。如果注釋掉第一行,print()
函數(shù)發(fā)送的數(shù)據(jù)會亂碼,因為fputc()
函數(shù)是實現(xiàn)一個字符的輸出,printf()
輸出很多個字符時,注釋掉第一行代碼將不再等待上一字符發(fā)送完成,將會一直發(fā)送疊加,導致亂碼。使用微庫法時,不能屏蔽掉fputc
函數(shù),只需要屏蔽1個預處理、 2個定義、3個函數(shù)。文章來源:http://www.zghlxwxcb.cn/news/detail-618130.html
/* MDK下需要重定義fputc函數(shù), printf函數(shù)最終會通過調(diào)用fputc輸出字符串到串口 */
int fputc(int ch, FILE *f)
{
while ((USART_UX->SR & 0X40) == 0); /* 等待上一個字符發(fā)送完成 */
USART_UX->DR = (uint8_t)ch; /* 將要發(fā)送的字符 ch 寫入到DR寄存器 */
return ch;
}
#endif
4.總結(jié)(了解)
文章來源地址http://www.zghlxwxcb.cn/news/detail-618130.html
到了這里,關(guān)于【13】STM32·HAL庫-正點原子SYSTEM文件夾 | SysTick工作原理、寄存器介紹 | printf函數(shù)使用、重定向的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!