• 通过串口实现printf函数,中断实现串口数据接收


         stm32的工程可以直接使用C标准库函数,其中printf函数没有完全实现,预留了一个后门fputc函数,可以通过实现fputc往串口打印从而实现printf的功能。

     1.fputc格式:

    int fputc(int ch,FILE *F) {     //...... }

    //stm32开发板上运行程序,如果主机运行了调试器,程序就会使用主机的输入输出设备

    //这是方式叫半主机模式,printf如果要通过串口打印,必须关闭半主机模式 #pragma import(__use_no_semihosting)

    struct __FILE{     int handle; };

    FILE __stdout;

    //定义_sys_exit函数避免使用半主机模式

    void _sys_exit(int x) {     x = x; } //重定义fputc

    int fputc(int ch,FILE *F) {     //发送     USART_SendData(USART1,ch);    

     //等待上一个数据发送完成

    while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);        return ch; }

    ———————————————————————————————————————————

    2.使用中断实现串口的接收

        由于串口何时发送数据由CPU决定,不存在无效等待的问题,可以不使用中断,但是串口的接收不由CPU决定何时接收,如果还使用轮询就会存在大量无效等待,此时要使用中断提供效率。

        串口中断和定时器中断类似,需要配置中断开关和NVIC。

    NVIC_Init(...);//初始化函数

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断

        在串口中断处理函数中完成数据的接收

    void USART1_IRQHandler(void) {    

     //判断是否为接收中断 ---------- USART_GetITStatus(USART1, USART_IT_RXNE);  

       //接收数据 ------------------- data = USART_ReceiveData(USART1);   

      //清除中断标志 --------------- USART_ClearITPendingBit(USART1, USART_IT_RXNE);

    }

    练习:

        为串口中断实现数据接收和控制命令控制蜂鸣器主要功能函数

    1. #include <stm32f4xx.h>
    2. #include <usart.h>
    3. #include <stdio.h>
    4. #include <string.h>
    5. #include <includes.h>
    6. //stm32开发板上运行程序,如果主机运行了调试器,程序就会使用主机的输入输出设备
    7. //这是方式叫半主机模式,printf如果要通过串口打印,必须关闭半主机模式
    8. #pragma import(__use_no_semihosting)
    9. struct __FILE{
    10. int handle;
    11. };
    12. FILE __stdout;
    13. //定义_sys_exit函数避免使用半主机模式
    14. void _sys_exit(int x)
    15. {
    16. x = x;//这里的赋值没有实际意义,避免空函数
    17. }
    18. //重定义fputc
    19. int fputc(int ch,FILE *F)
    20. {
    21. //等待上一个数据发送完成
    22. while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
    23. //发送
    24. USART_SendData(USART1,ch);
    25. return ch;
    26. }
    27. void usart1_init(void)
    28. {
    29. GPIO_InitTypeDef GPIO_InitStruct;
    30. USART_InitTypeDef USART_InitStruct;
    31. NVIC_InitTypeDef NVIC_InitStruct;
    32. //1.开启GPIOA和USART1时钟
    33. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
    34. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    35. //2.配置PA9 PA10为串口功能
    36. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
    37. GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
    38. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//高速
    39. GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
    40. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
    41. GPIO_Init(GPIOA,&GPIO_InitStruct);
    42. GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
    43. GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
    44. //3.初始化串口 8N1
    45. USART_InitStruct.USART_BaudRate = 115200;//波特率
    46. USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8位数据位
    47. USART_InitStruct.USART_StopBits = USART_StopBits_1;//1位停止位
    48. USART_InitStruct.USART_Parity = USART_Parity_No;//无校验
    49. USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//发送接收模式
    50. USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
    51. USART_Init(USART1,&USART_InitStruct);
    52. //4.开启串口接收中断(清除中断标志)
    53. USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    54. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    55. //5.初始化NVIC
    56. NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
    57. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x2;//抢占优先级
    58. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;//响应优先级
    59. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
    60. NVIC_Init(&NVIC_InitStruct);
    61. //.使能串口
    62. USART_Cmd(USART1,ENABLE);
    63. }
    64. //发送一个字符(轮询)
    65. void uart1_putc(char ch)
    66. {
    67. //等待上一个数据发送完成
    68. while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
    69. USART_SendData(USART1,ch);
    70. }
    71. //发送字符串
    72. void uart1_puts(const char *s)
    73. {
    74. while(*s){
    75. uart1_putc(*s++);
    76. }
    77. }
    78. volatile u32 uart_flag = 0;//记录串口是否收到了一个完整的数据 1---完整
    79. volatile u8 uart_buf[64] = {0};//记录串口收到的数据
    80. volatile u32 uart_cnt = 0;//记录串口收到的数据长度
    81. //处理串口命令函数
    82. void parse_cmd(void)
    83. {
    84. while(1){
    85. if(uart_flag){
    86. //BEEP命令
    87. if(strstr((char *)uart_buf,"beep")){
    88. if(strstr((char *)uart_buf,"on")){
    89. BEEP = 1;
    90. printf("beep on!\r\n");
    91. }
    92. if(strstr((char *)uart_buf,"off")){
    93. BEEP = 0;
    94. printf("beep off!\r\n");
    95. }
    96. }
    97. else{//非法命令
    98. printf("unknow command = %s\r\n",(char *)uart_buf);
    99. }
    100. //处理完成标志清0,缓冲区清空,个数清0
    101. uart_flag = 0;
    102. memset((char *)uart_buf,0,sizeof(uart_buf));
    103. uart_cnt = 0;
    104. }
    105. }
    106. }
    107. //串口1中断处理函数
    108. void USART1_IRQHandler(void)
    109. {
    110. //u8 data;
    111. if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET){
    112. //接收串口数据
    113. uart_buf[uart_cnt++] = USART_ReceiveData(USART1);
    114. //判断数据是否接收完成 ------ 以*结束
    115. if(uart_buf[uart_cnt-1]=='*'||uart_cnt>=sizeof(uart_buf)){
    116. uart_flag = 1;
    117. }
    118. //原路发回
    119. //uart1_putc(data);
    120. USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    121. }
    122. }

  • 相关阅读:
    小程序如何关联公众号来发送模板消息
    开手游要选用怎么样的服务器
    经典算法之直接插入排序(DirectInsert Sort)
    c# 读写内存映射文件
    rust的排序
    go 1.18新特性(泛性 模糊测试 WorkSpace)
    【C++】基础语法(中)
    java(Collections工具类)
    卷积网络识别好莱坞明星
    猫头虎分享已解决Bug || **Eslint插件安装问题Unable to resolve eslint-plugin-猫头虎
  • 原文地址:https://blog.csdn.net/weixin_44651073/article/details/125629174