文章目录

  • 串口发送数据
  • 串口接受数据

串口发送数据

1、串口发送数据最直接的方式就是标准调用库函数 。

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展:

void Send_data(u8 *s)
{while(*s!='\0'){ while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET); USART_SendData(USART1,*s);s++;}
}

以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。

while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下:

void Send_data(USART_TypeDef * USARTx,u8 *s)
{while(*s!='\0'){ while(USART_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET); USART_SendData(USARTx,*s);s++;}
}

这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如UCOS,Freertos等),需考虑函数重入的问题。
当然也可以简单的实现把该函数复制一下,然后修改串口号也可以避免该问题。然而这个函数不能像printf那样传递多个参数,所以还可以在改进,最终程序如下:

void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
{const char *s;int d;   char buf[16];va_list ap;va_start(ap, Data);while ( * Data != 0 )     // 判断是否到达字符串结束符{                              if ( * Data == 0x5c )  //'\'{           switch ( *++Data ){case 'r':                 //回车符USART_SendData(USARTx, 0x0d);Data ++;break;case 'n':                 //换行符USART_SendData(USARTx, 0x0a); Data ++;break;default:Data ++;break;}    }else if ( * Data == '%'){           //switch ( *++Data ){    case 's':            //字符串s = va_arg(ap, const char *);for ( ; *s; s++) {USART_SendData(USARTx,*s);while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );}Data++;break;case 'd':   //十进制d = va_arg(ap, int);itoa(d, buf, 10);for (s = buf; *s; s++) {USART_SendData(USARTx,*s);while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );}Data++;break;default:Data++;break;}   }else USART_SendData(USARTx, *Data++);while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );}
}

该函数就可以像printf使用可变参数,方便很多。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。
2、 直接使用printf函数。
很多朋友都知道想要STM32要直接使用printf不行的。需要加上以下的重映射函数;
如果不想添加以上代码,也可以勾选以下的Use MicroLI选项来支持printf函数使用:

串口接受数据

串口接收最后应有一定的协议,如发送一帧数据应该有头标志或尾标志,也可两个标志都有。
这样在处理数据时既能能保证数据的正确接收,也有利于接收完后我们处理数据。串口的配置在这里就不在赘述,这里我以串口2接收中断服务程序函数且接收的数据包含头尾标识为例。

#define Max_BUFF_Len 18
unsigned char Uart2_Buffer[Max_BUFF_Len];
unsigned int Uart2_Rx=0;
void USART2_IRQHandler()
{if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 {USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);     //接收串口1数据到buff缓冲区Uart2_Rx++; if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len)    //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收){if(Uart2_Buffer[0] == '+')                      //检测到头标识是我们需要的 {printf("%s\r\n",Uart2_Buffer);        //这里我做打印数据处理Uart2_Rx=0;                                   } else{Uart2_Rx=0;                                   //不是我们需要的数据或者达到最大接收数则开始重新接收}}}
}

数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。
这样做的有以下好处:
1.可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改
2.可以接受指定的数据
3.防止接收的数据使数组越界
这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。

以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。
所以以DMA形式配合串口的IDLE(空闲中断)来接受数据将会大大的提高CPU的利用率,减少系统资源的消耗。首先还是先看代码。

#define DMA_USART1_RECEIVE_LEN 18
void USART1_IRQHandler(void)
{     u32 temp = 0;  uint16_t i = 0;  if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  {  USART1->SR;  USART1->DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志    DMA_Cmd(DMA1_Channel5,DISABLE);  temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小 for (i = 0;i < temp;i++)  {  Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i];  }  //设置传输数据长度  DMA_SetCurrDataCounter(DMA1_Channel5,DMA_USART1_RECEIVE_LEN);  //打开DMA  DMA_Cmd(DMA1_Channel5,ENABLE);  }
}

之前的串口中断是一个一个字符的接收,现在改为串口空闲中断,就是一帧数据过来才中断进入一次。而且接收的数据时候是DMA来搬运到我们指定的缓冲区(也就是程序中的USART1_RECEIVE_DMABuffer数组),是不占用CPU时间资源的。

最后在讲下DMA的发送:

#define DMA_USART1_SEND_LEN 64
void DMA_SEND_EN(void)
{DMA_Cmd(DMA1_Channel4, DISABLE);      DMA_SetCurrDataCounter(DMA1_Channel4,DMA_USART1_SEND_LEN);   DMA_Cmd(DMA1_Channel4, ENABLE);
}

这里需要注意下DMA_Cmd(DMA1_Channel4,DISABLE)函数需要在设置传输大小之前调用一下,否则不会重新启动DMA发送。

STM32串口发送数据和接收数据方式总结相关推荐

  1. STM32串口发送16进制数据

    方法一(用printf函数) 下面演示两个示例 //说明:用u8或unsigned char都能正常发送//示例 1 u8 send1=0x55; printf("%c",send ...

  2. stm32串口发送数据的配置,以及通过串口发送结构体数组总是多一个00字节的问题

    最近用stm32编写串口发送程序,在硬件方面需要做如下准备: 1.stm32开发板,这里我的是stm32f030f4p4开发板,单片机的串口发送的引脚为PA9-TX,PA10-RX. 2.为了调试串口 ...

  3. 向STM32串口发送数据的标准函数

    向STM32串口发送数据的标准函数 例子:1 void UART_Send_Message(u8 *Data,u8 lenth) {while(lenth--){USART_SendData(USAR ...

  4. MATLAB输出串口发送所需十六进制数据

    MATLAB输出串口发送所需十六进制数据   在FPGA设计过程中,有时需要与MATLAB进行联合调试,需要从MATLAB导出数据,再从PC端通过串口发送给FPGA,对数据进行处理后再返回PC端.串口 ...

  5. unity网络实战开发(丛林战争)-前期知识准备(003-开发服务器端的发送数据和接收数据)

    使用工具:VS2015 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下服务器端的发送数据和接收数据. 上篇文章 ...

  6. Java基础知识强化之网络编程笔记03:UDP之UDP协议发送数据 和 接收数据

    1. UDP协议发送数据 和 接收数据 UDP协议发送数据: • 创建发送端的Socket对象 • 创建数据,并把数据打包 • 调用Socket对象的发送方法,发送数据包 • 释放资源  UDP协议接 ...

  7. STM32 串口发送乱码问题

    STM32 串口发送乱码问题 一.问题状况: 显示为一堆乱码,

  8. STM32移植RT-Thread后的串口在调试助手上出现:(mq != RT_NULL) assert failed at rt_mq_recv:2085和串口只发送数据不能接收数据问题

    STM32移植RT-Thread后的串口在调试助手上出现:(mq != RT_NULL) assert failed at rt_mq_recv:2085的问题讨论:http://www.rt-thr ...

  9. STM32串口发送接收数据

    目录 1.串口通信 2.串口的结构体 3.如何配置串口的发送 4.通过串口向电脑发送ok字符 5.封装发送字符串函数 6.重定向printf串口发送 7.串口输入控制LED灯开关 遇到的问题 1.串口 ...

最新文章

  1. 【hibernate系列】采用p6spy+SQLProfiler完整显示hibernate的S...
  2. 互联网算法面试高频题目
  3. delphi 画 带箭头的线
  4. AIX命令参考大全,卷 4,n - r
  5. mobilenet V1
  6. 终于有人把Docker讲清楚了
  7. android 使用画布实现电子签名板功能并保存到本地
  8. 4G-LTE技术总结
  9. 某种家庭式光伏发电系统设计
  10. U盘中毒后文件夹变成exe怎么办
  11. 医院预算目标分解公式
  12. 数据立方体的基本计算
  13. 工作室培训第一周总结
  14. JavaScript基础学习——CSS预处理Less
  15. 高德地图 sdk 加载 geoserver 发布的瓦片地图服务
  16. Binding的学习与使用
  17. Metasploit的使用-入门
  18. Linux连接redis数据库
  19. [GYCTF2020]Blacklist
  20. myeclipse 10.0下载及安装

热门文章

  1. nRF52840 VDDH 供电使用方法
  2. 在 CSS 中设置 cellpadding 和 cellspacing?
  3. Android 上架谷歌市场
  4. ES5、ES6的浏览器兼容性
  5. Snap股市暴涨暴跌,眼红嫉妒的中国社交路在何方?
  6. 解析SQL Server 2008的精妙之处
  7. Cocos2d-导演、场景、层、精灵
  8. » VIM Adventures : 边玩游戏边学 VIM Wow! Ubuntu
  9. 流量红利消退,汽车互联网该怎么玩?
  10. EtherCAT igh主站控制埃斯顿伺服(csp模式)