关于单片机串口接收一些数据的处理

  1. 在工业上,一般采用485通讯,那么主控发出的的数据,单片机是怎么接受的呢?在网络通讯中,一般用socket通讯,那么一个输出流字节流是怎么被单片机接受的呢?

  2. 串口有接收中断,那么接受一个字节中断一次,那么单片机就别工作了,在一些实时性达到us级别的场合下是严重不靠谱的。比如误差不超过1ms,超过1ms可能会使的加工产生1mm的误差,那么在精密电子,误差都是nm级别的,你1mm直接就gg。

  3. 串口接受常用的中断有寄存器非空中断,这也是常用的中断。就是DR中有一字节数据就产生中断,modbus485就是这种中断,然后把每一个字节存放到数据缓冲区,在20ms(人为设置)没有收到数据就表示一帧数据接受完成。接受完成后在最后一次中断中去处理。关于modbus485的帧结构,查资料就行。

  1. 那么socket字节流呢?wifi,4g,蓝牙一般是串口,iic,spi等。spi速度最快,iic单向,串口配置简单,我看了一下,目前看到的都是串口。2m的字节流就太费中断了,所以采用uart——DMA通讯。IDLE这个中断就是在一个字节时间中没有收到数据就会产生中断,也就是总线空闲中断。总线空闲了再去处理这一批数据。

  1. 关于DMA技术,就是不耗费cpu资源把数据从DR放到缓冲区,通过总线技术实现。

一种串口接收的灵活使用处理:


//这里使用的是串口接收一字节数据就产生中断,然后根据帧头帧尾判断接收和发送
void DTU_data(u8 res)
{     
   //检测到帧头,开始接收
      if(res=='$' && len_reply==0)
       {
         len_reply=1;        
       }
     //把数据放到缓冲
       if(len_reply!=0)
       {
         DTU_reply[len_reply]=res;
        len_reply++;
       }
     //检测到帧尾,把数据从缓冲中取出,拼接成字符串,缓冲是全局变量,放在类中建议private
      if(res=='#')
      {  
         char *str=(char *)malloc(len_reply);//分配地址
         strcat(str,&DTU_reply[i]);
         DTU_send_char(str);//将接收到的字符串输出
         len_reply=0;
         free(str);//释放地址
      }
}
//malloc原理:从变量区寻找未被占用的空间,参数为空间大小。对了,字节占用一个地址。有多少地址就有多少字节,无论电脑,裸板,嵌入式还是别的。

如何使用stm32的标准库配置DMA:


/*
1.确定DMA的通道,stm32一般是2个DMA,外设和内存有各自对应的通道,可以查看相关手册
2.串口2为DMA1的5和6通道。5发,6收
3.流程直接看代码
4.串口的配置就正常配置,随便找个例程就有
*/
void init_DMA(unsigned char *U2_TXBUF)
{
   //使能DMA外设
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel6);//串口2的DMA数据通道
         //相应的DMA配置
    DMA_DeInit(DMA1_Channel6);   //将DMA的通道5寄存器重设为缺省值  串口2对应的是DMA通道16
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART2->DR; //DMA外设usart基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)u2tx_buf;  //DMA内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存
    DMA_InitStructure.DMA_BufferSize = U2_TXBUF;  //DMA通道的DMA缓存的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_Low;//DMA通道 x拥有低优先级 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道6没有设置为内存到内存传输
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道
    USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);   //使能串口2 DMA接收
    DMA_Cmd(DMA1_Channel6, ENABLE);  //正式驱动DMA传输
    //DMA_SetCurrDataCounter(DMA1_Stream6, byteLen);//初始化内存地址
}
//配置好之后串口2有数据过来就会自动放到缓冲区,缓冲区收一个地址增一个,满了就出问题了,所以要在满之前取出
//取的话有串口空闲中断和DMA缓冲区满中断两种方法,建议第一种

提示:中断有两种,一种是硬件中断,一种是软件中断。裸机开发都是硬件中断,带有系统后是软件中断和硬件中断共同使用,系统上的应用是无法访问任何系统资源的,它们必须通过系统调用,而系统调用是软件中断。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值