固件库内的函数是以STM32F10XXX内的每一个模块而设计的,它们给用户的感觉直观而灵活,使用户能够更方便的配置STM32F10XXX寄存器。这种针对于模块而编写的固件库函数包含“数据结构”和“操作寄存器算法”两个方面的设计。它们被实现的方式值得我学习,如USART_Init()函数能够通用于如USARTx[x=1,2,3,]的每一个通道,而不必分别为每一个通道都编写一个函数。
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); |
根据USART_InitStruct结构体参数内的元素初始化USARTx外设。
typedef struct { __IO uint16_t SR; uint16_t RESERVED0; __IO uint16_t DR; uint16_t RESERVED1; __IO uint16_t BRR; uint16_t RESERVED2; __IO uint16_t CR1; uint16_t RESERVED3; __IO uint16_t CR2; uint16_t RESERVED4; __IO uint16_t CR3; uint16_t RESERVED5; __IO uint16_t GTPR; uint16_t RESERVED6; } USART_TypeDef; |
typedef struct { uint32_t USART_BaudRate; //USART传输数据的波特率值 uint16_t USART_WordLength; //USART传输数据的长度 uint16_t USART_StopBits; //USART传输数据的停止位数 uint16_t USART_Parity; //USART校验位 uint16_t USART_Mode; //USART传送和接收模式 uint16_t USART_HardwareFlowControl; //USART硬件控制模式设置 } USART_InitTypeDef; |
#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif |
功能:assert_param()宏用来检查函数参数。在定义了USE_FULL_ASSERT情况下,如果expr为假,就会调用assert_failed输出正在调用assert_param宏的文件名及调用asser_param宏的行号。如果expr为真,不返回任何值。如果没有定义USE_FULL_ASSERT,则该宏不返回任何值。__FILE__, __LINE__属C中定义的宏,表示当前文件名及所在行的行号。
参数:expr可以为任何逻辑表达式。expr一般为宏,这个宏列举了该参数的所有情况,如果该参数在这些情况之内则expr为真,否则为假。
assert_failed:这个函数需要用户在主函数文件(如main.c)中定义,如:
void assert_failed(uint8_t* file, uint32_t line) { //Print DEBUG information printf(“%s ‘s %d line parameters error \n”); while (1){ } } |
断言的作用是供用户在调试(DEBUG)模式下更加方便的找到错误,在Debug中设置或者在程序中定义诸如USE_FULL_ASSERT之类的宏,断言代码就会运行,断言的运行需要占用一部分时间。在Release模式下,断言就不在需要,就可以被关闭,断言就变为诸如assert_param(expr) ((void)0)一样的语句。《C编程精粹》中有讲断言强大功效的。
tmpreg = USARTx->CR2; tmpreg &= CR2_STOP_CLEAR_Mask; tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits; USARTx->CR2 = (uint16_t)tmpreg; |
读CR2的值于tmpreg中。CR2_STOP_CLEAR_Mask的值为0xCFFF,使tmpreg的bit[13:12]为00,其它位保持不变。tmpreg与USART_InitStuct结构体元素USART_StopBits作或运算,USART_StopBits的值为0x0000,0x0100,0x0200,0x0300类,它们除在bit[13:12]之上有特殊的状态值之外其它位都为0。目的是配置CR2的bit[13:12]位已得到停止位数。然后再将tmpreg的值赋给CR2寄存器。
tmpreg =USARTx->CR1; tmpreg &=CR1_CLEAR_Mask; tmpreg |=(uint32_t)USART_InitStruct->USART_WordLength |USART_InitStruct->USART_Parity | USART_InitStruct->USART_Mode; USARTx->CR1 = (uint16_t)tmpreg; |
读CR1的值于tmpreg中。CR1_CLEAR_Mask的值为0xE9F3,与tmpreg作与运算使得bit[12](M),bit[10:9](PCE,PS),bit[3:2](TE,RE)这些需要被配置的位的值为0,00,00。然后与只设置了bit[12],bit[10:9],bit[3:2]值而其它位皆为0的数据位数位(USART_WordLength)、校验位(USART_Parity)、发/收模式位(USART_Mode)的状态值作或运算。然后将配置值tmpreg赋给CR1。
根据USART_InitStruct结构体参数内的USART_WordLength、USART_Parity、USART_Mode元素值分别配置CR1的bit[12,10:9,3:2]就得到相应的数据长度、校验方式、USARTx的工作模式。
tmpreg =USARTx->CR3; tmpreg &=CR3_CLEAR_Mask; tmpreg |=USART_InitStruct->USART_HardwareFlowControl; USARTx->CR3 = (uint16_t)tmpreg; |
usartxbase =(uint32_t)USARTx; if (usartxbase == USART1_BASE){ apbclock =RCC_ClocksStatus.PCLK2_Frequency; }else{ apbclock = RCC_ClocksStatus.PCLK1_Frequency; } |
由波特率和时钟频率计算配置BRR的值
可配置的BRR位为bit[15:0],配置给BRR的值称为USARTDIV,bit[15:4]为USARTDIV整数部分,bit[3:0]为USARTDIV小数部分。其中 ,integerdivider = ((0x19 * apbclock) / (0x04 * (USART_InitStruct->USART_BaudRate))); tmpreg = (integerdivider / 0x64) << 0x04; fractionaldivider = integerdivider - (0x64 * (tmpreg >> 0x04)); tmpreg |= ((((fractionaldivider * 0x10) + 0x32) / 0x64)) & ((uint8_t)0x0F); USARTx->BRR = (uint16_t)tmpreg; |