1.CubeMX配置

  1. /**
  2. * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  3. * 输入参数: 无
  4. * 返 回 值: 无
  5. * 说 明:无
  6. */
  7. int fputc(int ch, FILE *f)
  8. {
  9. HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
  10. return ch;
  11. }
  12. /**
  13. * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  14. * 输入参数: 无
  15. * 返 回 值: 无
  16. * 说 明:无
  17. */
  18. int fgetc(FILE * f)
  19. {
  20. uint8_t ch = 0;
  21. while(HAL_UART_Receive(&huart3,&ch, 1, 0xffff)!=HAL_OK);
  22. return ch;
  23. }

串口配置
其它时钟和以前一样,配置为72MHZ即可
image.png
串口的基本信息查看
11.串口通信及DS18B20使用

2.串口操作

21.串口发送

(1)阻塞模式串口发送
MCU的CPU一个字节一个字节的发送丢给串口模块,然后看着串口模块将这个字节发送出去,然后CPU去拿下一个字节丢给串口模块。直到本次发送的所有自己全部发送完,然后才去做其他事情。
(2)中断模式串口发送
MCU的CPU向串口模块丢一个字节,然后串口模块慢慢发,CPU丢完这个字节后跳出去做其他事情,等串口模块发完这个字节后产生一个中断,中断会通知CPU过来继续丢下一个字节。

阻塞式发送:HAL_UART_Transmit
阻塞式接收:HAL_UART_Receive
总结:阻塞式发送实际用的很多,因为编程简单。缺陷就是浪费了高速CPU的部分性能,没有追求到串口发送和整个系统性能的最高。

  1. #ifdef __GNUC__
  2. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  3. #else
  4. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  5. #endif
  6. /**
  7. * @brief Retargets the C library printf function to the USART.
  8. * @param None
  9. * @retval None
  10. */
  11. PUTCHAR_PROTOTYPE
  12. {
  13. /* Place your implementation of fputc here */
  14. /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  15. HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
  16. return ch;
  17. }

2.2串口接收

阻塞式串口接收
中断式串口接收
一般使用中断串口接收

注意在Cube中打开中断
如下是中断处理程序

注意要开启中断

  1. HAL_UART_Receive_IT(&huart1, &receive_char, 1);
  2. //开启中断
  3. uint8_t receive_char;
  4. //这个就是HAL库对接的中断处理函数
  5. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  6. {
  7. if(huart->Instance == USART1)
  8. {
  9. //这里就是真正的中断处理代码
  10. //receive_char 是全局变量 接收
  11. //这里的处理就是接收到一个字节,原封不动的发出去
  12. HAL_UART_Transmit(&huart1, &receive_char, 1,0xFF);
  13. //确定本次接收完毕,同时开启下一次接收
  14. while(HAL_UART_Receive_IT(&huart1, &receive_char, 1) != HAL_OK);
  15. }
  16. }
  17. HAL_UART_Receive_IT(&huart1, &receive_char, 1);

2.3串口接收和处理

指令:
add
sub
指令结束符:
‘;’
指令中遇到回车和空格、Tab怎么办? 不进行处理
实现思路分析:

  1. //这个就是HAL库对接的中断处理函数
  2. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  3. {
  4. if(huart->Instance == USART1)
  5. {
  6. rev_buf[ind++] = receive_char;
  7. //这里就是真正的中断处理代码
  8. //receive_char 是全局变量 接收
  9. //这里的处理就是接收到一个字节,原封不动的发出去
  10. //HAL_UART_Transmit(&huart1, &receive_char, 1,0xFF);
  11. //确定本次接收完毕,同时开启下一次接收
  12. while(HAL_UART_Receive_IT(&huart1, &receive_char, 1) != HAL_OK);
  13. }
  14. }
  1. uint8_t receive_char;
  2. uint8_t rev_buf[20]; //串口接收到字符串暂存到rev_buf
  3. uint8_t ind = 0; //ind 为buf的索引
  4. uint8_t i = 0;
  5. //开启中断
  6. HAL_UART_Receive_IT(&huart1, &receive_char, 1);
  7. //循环
  8. while (1)
  9. {
  10. //在主循环中处理接收到的buf指令
  11. //第一步,先遍历整个buf,找到是否有分号
  12. for (i = 0; i < ind; i++)
  13. {
  14. if (rev_buf[i] == ';')
  15. {
  16. //找到了,说明已经接收完一个命令了,可以进行处理了
  17. if ((strncmp((char*)rev_buf, "add;", 4)) == 0)
  18. {
  19. //执行add指令即可
  20. printf("增加");
  21. }
  22. else if ((strncmp((char*)rev_buf, "sub;", 4)) == 0)
  23. {
  24. //执行add指令即可
  25. printf("减少");
  26. }
  27. else
  28. {
  29. printf("unknown");
  30. }
  31. //指令识别执行完成,要把buf和index清空
  32. memset(rev_buf, 0, 20);
  33. ind = 0;
  34. }
  35. }
  36. HAL_Delay(200);
  37. /* USER CODE END WHILE */
  38. /* USER CODE BEGIN 3 */
  39. }

2.4串口总结

(1)基于HAL库和CubeMX工具的开发,用起来很简单
(2)遇到问题大部分是因为不熟悉这一套,是最耗时间的
(3)解决问题靠调试能力功底、经验等,是核心竞争力
(4)后续发展:字符串处理拓展
(5)未尽事宜:串口的DMA发送和接收

3.按键中断

PA0为中断按键
PG6为LED

3.1 配置

时钟配置就不说了
将A0设置为外部中断
image.png
引脚配置为下降沿触发

image.png
NVIC使能
image.png
如需要配置优先级 可以在NVIC中进行配置
重写中断程序即可
翻转LED

  1. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  2. {
  3. if(GPIO_Pin == Key_Pin)
  4. {
  5. HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  6. }
  7. }

3.2 总结
(1)用Cube生成中断很方便
(2)很多细节都进行了隐藏,还是比较难找的