本帖最后由 radio2radio 于 2018-7-14 23:51 编辑
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
简单的要求是,USART1和USART2之间互相转发。
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
1. 配置管脚,使用BluePill最小板,PC13接有LED:
MCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。
2. 配置时钟,重点已经标出:
3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
(USART2也要同样配置)
(然后,生成工程代码)
4. 添加代码
4.1 在main的初始化部分,添加接收中断使能:
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
- __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
- /* USER CODE BEGIN 0 */
- #define UART_BUFFER_SIZE 64 //here must be 2^n
- struct bufer_st {
- unsigned int in; // Next In Index
- unsigned int out; // Next Out Index
- char buffer [UART_BUFFER_SIZE]; // Buffer
- };
- static struct bufer_st uart1buffer = { 0, 0, };
- static struct bufer_st uart2buffer = { 0, 0, };
- /* USER CODE END 0 */
复制代码
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**
- * @brief This function handles USART1 global interrupt.
- */
- void USART1_IRQHandler(void)
- {
- /* USER CODE BEGIN USART1_IRQn 0 */
- struct bufer_st *p;
- /* USER CODE END USART1_IRQn 0 */
- HAL_UART_IRQHandler(&huart1);
- /* USER CODE BEGIN USART1_IRQn 1 */
- p = &uart1buffer; //use UART1 buffer
-
- //raed UART1
- if (USART1->SR & UART_IT_RXNE) // read interrupt
- {
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
- p->in++;
- }
- }
- //send to UART2
- if (p->in != p->out)
- {
- USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
- p->out++;
- }
- /* USER CODE END USART1_IRQn 1 */
- }
- /**
- * @brief This function handles USART2 global interrupt.
- */
- void USART2_IRQHandler(void)
- {
- /* USER CODE BEGIN USART2_IRQn 0 */
- struct bufer_st *p;
- /* USER CODE END USART2_IRQn 0 */
- HAL_UART_IRQHandler(&huart2);
- /* USER CODE BEGIN USART2_IRQn 1 */
- p = &uart2buffer; //use UART2 buffer
-
- //raed UART2
- if (USART2->SR & UART_IT_RXNE) // read interrupt
- {
- USART2->SR &= ~UART_IT_RXNE; // clear interrupt
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
- {
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
- p->in++;
- }
- }
- //send to UART1
- if (p->in != p->out)
- {
- USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
- p->out++;
- }
- /* USER CODE END USART2_IRQn 1 */
- }
复制代码
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
大功告成了!! 编译后烧录。
测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)
最后,完整的工程见附件。
|
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2.写入dr寄存器很快,但是发送完成又是另外一会事情
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞