-
在工业上,一般采用485通讯,那么主控发出的的数据,单片机是怎么接受的呢?在网络通讯中,一般用socket通讯,那么一个输出流字节流是怎么被单片机接受的呢?
-
串口有接收中断,那么接受一个字节中断一次,那么单片机就别工作了,在一些实时性达到us级别的场合下是严重不靠谱的。比如误差不超过1ms,超过1ms可能会使的加工产生1mm的误差,那么在精密电子,误差都是nm级别的,你1mm直接就gg。
-
串口接受常用的中断有寄存器非空中断,这也是常用的中断。就是DR中有一字节数据就产生中断,modbus485就是这种中断,然后把每一个字节存放到数据缓冲区,在20ms(人为设置)没有收到数据就表示一帧数据接受完成。接受完成后在最后一次中断中去处理。关于modbus485的帧结构,查资料就行。
-
那么socket字节流呢?wifi,4g,蓝牙一般是串口,iic,spi等。spi速度最快,iic单向,串口配置简单,我看了一下,目前看到的都是串口。2m的字节流就太费中断了,所以采用uart——DMA通讯。IDLE这个中断就是在一个字节时间中没有收到数据就会产生中断,也就是总线空闲中断。总线空闲了再去处理这一批数据。
-
关于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缓冲区满中断两种方法,建议第一种
提示:中断有两种,一种是硬件中断,一种是软件中断。裸机开发都是硬件中断,带有系统后是软件中断和硬件中断共同使用,系统上的应用是无法访问任何系统资源的,它们必须通过系统调用,而系统调用是软件中断。