- void uart1_init()
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- USART_InitTypeDef USART_InitStructure = {0};
- __RCC_GPIOA_CLK_ENABLE();
- __RCC_UART1_CLK_ENABLE();
- PA08_AFx_UART1TXD();
- PA09_AFx_UART1RXD();
- GPIO_InitStructure.Pins = GPIO_PIN_8;
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
- GPIO_InitStructure.Pins = GPIO_PIN_9;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
-
- USART_InitStructure.USART_BaudRate = 115200;
- USART_InitStructure.USART_Over = USART_Over_16;
- USART_InitStructure.USART_Source = USART_Source_PCLK;
- USART_InitStructure.USART_UclkFreq = SystemCoreClock;
- USART_InitStructure.USART_StartBit = USART_StartBit_FE;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No ;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(CW_UART1, &USART_InitStructure);
- }
- int32_t main(void)
- {
- uint8_t uart_msg[10];
- uint8_t uart_msg_len = 0,uart_msg_index = 0;
- RCC_HSI_48M_init();
- RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
- RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
- uart1_init();
- while (1)
- {
- do
- {
- while(USART_GetFlagStatus(CW_UART1, USART_FLAG_RC) == RESET);
- USART_ClearFlag(CW_UART1, USART_FLAG_RC);
- if(USART_GetFlagStatus(CW_UART1, USART_FLAG_PE|USART_FLAG_FE))
- {
- USART_ClearFlag(CW_UART1, USART_FLAG_PE|USART_FLAG_FE);
- uart_msg_len = 0x00;
- }
- else
- {
- uart_msg[uart_msg_len] = USART_ReceiveData_8bit(CW_UART1);
- uart_msg_len++;
- }
- }
- while(uart_msg[uart_msg_len-1] != '\n' && uart_msg_len < 10);
- uart_msg_index = 0;
- while(uart_msg_index < uart_msg_len)
- {
- USART_SendData_8bit(CW_UART1, uart_msg[uart_msg_index]);
- uart_msg[uart_msg_index] = 0;
- while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXE) == RESET);
- uart_msg_index += 1;
- }
- while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXBUSY) == SET);
- uart_msg_len = 0;
- }
- }
运行效果
接下来实现一下printf重定向到串口,这样以后就方便输出调试信息了,在MDK中实现这个功能最简单的方法就是先在工程设置中勾选Use MacroLib
包含stdio.h后重写fputc就行了
- int fputc(int ch, FILE *f)
- {
- while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TXBUSY) == SET);
- USART_SendData_8bit(CW_UART1,ch&0xFF);
- return ch;
- }
- int32_t main(void)
- {
- uint8_t testnum = 0;
- RCC_HSI_48M_init();
- RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
- RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
- uart1_init();
- while (1)
- {
- printf("printf重定向测试 %d",testnum++);
- yuyy_delay_ms(1000);
- }
- }
运行效果
接下来试试中断模式下的数据收发,CW32L031串口支持的中断如下
CW32L031的串口有个内置的定时器,可以实现接收空闲检测,这个就方便了很多,不用自己再用定时器检测接收超时,可以实现不定长的数据接收
- void uart1_init()
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- USART_InitTypeDef USART_InitStructure = {0};
- __RCC_GPIOA_CLK_ENABLE();
- __RCC_UART1_CLK_ENABLE();
- PA08_AFx_UART1TXD();
- PA09_AFx_UART1RXD();
- GPIO_InitStructure.Pins = GPIO_PIN_8;
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
- GPIO_InitStructure.Pins = GPIO_PIN_9;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
-
- USART_InitStructure.USART_BaudRate = 115200;
- USART_InitStructure.USART_Over = USART_Over_16;
- USART_InitStructure.USART_Source = USART_Source_PCLK;
- USART_InitStructure.USART_UclkFreq = SystemCoreClock;
- USART_InitStructure.USART_StartBit = USART_StartBit_FE;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No ;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(CW_UART1, &USART_InitStructure);
- USART_TimerModeConfig(CW_UART1,USART_TimerMode_Idle);
- USART_SetAutoReload(CW_UART1,480);
- USART_ITConfig(CW_UART1, USART_IT_RC, ENABLE);
- USART_ITConfig(CW_UART1, USART_IT_TIMOV, ENABLE);
- NVIC_SetPriority(UART1_IRQn, 0);
- NVIC_EnableIRQ(UART1_IRQn);
- }
- #define UART_BUFFER_LEN 20
- uint8_t uart_buffer[UART_BUFFER_LEN] = {0};
- uint8_t uart_rxindex = 0;
- uint8_t uart_rxlen = 0;
- uint8_t uart_txindex = 0;
- uint8_t uart_txlen = 0;
- void readrxtotxbuffer()
- {
- uart_txlen += uart_rxlen;
- uart_rxlen = 0;
- USART_ITConfig(CW_UART1, USART_IT_TXE, ENABLE);
- }
- void UART1_IRQHandler(void)
- {
- if(USART_GetITStatus(CW_UART1, USART_IT_RC) != RESET)
- {
- uart_buffer[uart_rxindex++] = USART_ReceiveData_8bit(CW_UART1);
- if(uart_rxindex == UART_BUFFER_LEN)
- uart_rxindex = 0;
- uart_rxlen++;
- USART_ClearITPendingBit(CW_UART1, USART_IT_RC);
- }
- if(USART_GetITStatus(CW_UART1, USART_IT_TIMOV) != RESET || uart_rxlen == 10)
- {
- USART_ClearITPendingBit(CW_UART1, USART_IT_TIMOV);
- USART_TimerModeConfig(CW_UART1,USART_TimerMode_Idle);
- readrxtotxbuffer();
- }
- if(USART_GetITStatus(CW_UART1, USART_IT_TXE) != RESET)
- {
- if(uart_txlen > 0)
- {
- USART_SendData_8bit(CW_UART1, uart_buffer[uart_txindex++]);
- if(uart_txindex == UART_BUFFER_LEN)
- uart_txindex = 0;
- uart_txlen--;
- }
- else
- {
- USART_ITConfig(CW_UART1, USART_IT_TXE, DISABLE);
- }
- USART_ClearITPendingBit(CW_UART1, USART_IT_TXE);
- }
- }
需要注意的是当uart定时器溢出后需要再次配置定时器,不然后面不会再触发空闲中断,另外这个空闲时间的判定似乎有问题,原来配置的是48000,按照手册描述空闲时间=48000/48000000=1ms,但实际时间有500ms左右
运行结果
利用这个定时器还能实现自动侦测波特率
来实验一下,直接使用例程里的代码
- void uart1_init()
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- USART_InitTypeDef USART_InitStructure = {0};
- __RCC_GPIOA_CLK_ENABLE();
- __RCC_UART1_CLK_ENABLE();
- PA08_AFx_UART1TXD();
- PA09_AFx_UART1RXD();
- GPIO_InitStructure.Pins = GPIO_PIN_8;
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
- GPIO_InitStructure.Pins = GPIO_PIN_9;
- GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
- GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
-
- USART_InitStructure.USART_BaudRate = 115200;
- USART_InitStructure.USART_Over = USART_Over_16;
- USART_InitStructure.USART_Source = USART_Source_PCLK;
- USART_InitStructure.USART_UclkFreq = SystemCoreClock;
- USART_InitStructure.USART_StartBit = USART_StartBit_FE;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No ;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(CW_UART1, &USART_InitStructure);
- USART_SetAutoReload(CW_UART1, 0xFFFFFF);
- USART_TimerModeConfig(CW_UART1, USART_TimerMode_AutoBaudRate1);
- USART_ITConfig(CW_UART1, USART_IT_TIMOV | USART_IT_BAUD, ENABLE);
- NVIC_SetPriority(UART1_IRQn, 0);
- NVIC_EnableIRQ(UART1_IRQn);
- }
- uint8_t uart_baud_fin = 0;
- uint8_t uart_ov_count = 0;
- void readrxtotxbuffer()
- {
- uart_txlen += uart_rxlen;
- uart_rxlen = 0;
- USART_ITConfig(CW_UART1, USART_IT_TXE, ENABLE);
- }
- void UART1_IRQHandler(void)
- {
- uint32_t uart_baud_count = 0;
- if(uart_baud_fin == 0)
- {
- if(USART_GetITStatus(CW_UART1, USART_IT_TIMOV))
- {
- USART_ClearITPendingBit(CW_UART1, USART_IT_TIMOV);
- uart_ov_count += 1;
- }
- if(USART_GetITStatus(CW_UART1, USART_IT_BAUD))
- {
- uart_baud_count = (0x1000000*uart_ov_count + USART_GetCounter(CW_UART1)) / 4;
- CW_UART1->BRRI = (uint16_t)(uart_baud_count >> 4);
- CW_UART1->BRRF = (uint16_t)(uart_baud_count & 0x0F);
- USART_ClearITPendingBit(CW_UART1, USART_IT_BAUD);
- USART_ClearITPendingBit(CW_UART1, USART_IT_RC);
- USART_ITConfig(CW_UART1, USART_IT_RC, ENABLE);
- USART_TimerModeConfig(CW_UART1,USART_TimerMode_Idle);
- USART_SetAutoReload(CW_UART1, 480);
- uart_ov_count = 0;
- uart_baud_fin = 1;
- }
- }
- else
- {
- if(USART_GetITStatus(CW_UART1, USART_IT_RC) != RESET)
- {
- uart_buffer[uart_rxindex++] = USART_ReceiveData_8bit(CW_UART1);
- if(uart_rxindex == UART_BUFFER_LEN)
- uart_rxindex = 0;
- uart_rxlen++;
- USART_ClearITPendingBit(CW_UART1, USART_IT_RC);
- }
- if(USART_GetITStatus(CW_UART1, USART_IT_TIMOV) != RESET || uart_rxlen == 10)
- {
- USART_ClearITPendingBit(CW_UART1, USART_IT_TIMOV);
- USART_TimerModeConfig(CW_UART1,USART_TimerMode_Idle);
- readrxtotxbuffer();
- }
- if(USART_GetITStatus(CW_UART1, USART_IT_TXE) != RESET)
- {
- if(uart_txlen > 0)
- {
- USART_SendData_8bit(CW_UART1, uart_buffer[uart_txindex++]);
- if(uart_txindex == UART_BUFFER_LEN)
- uart_txindex = 0;
- uart_txlen--;
- }
- else
- {
- USART_ITConfig(CW_UART1, USART_IT_TXE, DISABLE);
- }
- USART_ClearITPendingBit(CW_UART1, USART_IT_TXE);
- }
- }
- }
运行效果
复位MCU修改上位机串口波特率
如果改变了消息头波特率计算就会出错
接下来简单说一下是如何实现的,先来了解一下串口数据的结构
先是起始帧为低电平,计数器在下降沿开始计数,当遇到上升沿停止计数,这时累积的计数结果就是起始帧加上开头这几个为0的bit的总计数,以上面的为例用F8作为消息头消息结构如下
0 00011111 1
用总计数结果除以4就得到了1个bit所用的计数,波特率计数器和UART定时器的时钟源都是UCLK,可以认为它们的频率相同,之后用这个结果重新设置波特率计数器就能达到自动侦测波特率的功能
如果上位机单独改变了消息头比如F0(00001111),这时候加上起始帧就有5个为0的bit,这时程序里还是按照4个去计算就会造成计算出的波特率不准确,因此在实际使用时要协商好作为判断波特率的消息头