中级会员
 
- 积分
- 289
- 金钱
- 289
- 注册时间
- 2014-1-2
- 在线时间
- 62 小时
|
50金钱
本帖最后由 llqzx 于 2016-7-13 10:13 编辑
这个是我联机FX2N和三菱编程软件得到的通信协议,当测试通信时,软件先发送 05 到下位机,下位机回复 06,然后上位机发送 02 30 30 45 30 32 30 32 03 36 43到下位机,下位机 回复 02 46 36 35 45 03 46 39……再依次进行,但是看监视到的数据和我实际的测试,有以下问题:
1,因为通信过程中可能单片机串口接收到的数据长度不一致,所以我采用了论坛里的空闲中断方式来接收,然后一帧数据接收完后触发中断,去判断帧头或者功能字是什么进行处理,比如判断 BUF[0]=0x05,就发送0x06,如果是BUF[0]=0x02,BUF[1]=0x30,……再发送别的,思路是这样,但是实际测试, 收到 05 发送 06 没问题,但是再收到一帧数据,就不进中断了,也不发送了,不知道什么原因。而且不知道哪里来的一个7f,看监视,像是单片机发出的,但是明明没有这个。用串口调试软件测试单片机没问题,连续发送都可以进中断,调试了好几天了没头绪。下面贴出代码和截图
void uart_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_Even;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
//相应的DMA配置
DMA_DeInit(DMA1_Channel5); //将DMA的通道5寄存器重设为缺省值 串口1对应的是DMA通道5
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设读取发送到内存
DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len; //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_Circular; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1 DMA接收
DMA_Cmd(DMA1_Channel5, ENABLE); //正式驱动DMA传输
USART_Cmd(USART1, ENABLE); //使能串口
USART_ClearFlag(USART1, USART_FLAG_TC);
}
//重新恢复DMA指针
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx, DISABLE ); //关闭USART1 TX DMA1 所指示的通道
DMA_SetCurrDataCounter(DMA_CHx,DMA_Rec_Len);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道
}
//发送len个字节.
//buf:发送区首地址
//len:发送的字节数
void Usart1_Send(u8 *buf,u8 len)
{
u8 t;
for(t=0;t<len;t++) //循环发送数据
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1,buf[t]);
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
u8 Res;
//串口中断函数
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收中断
{
DMA_Cmd(DMA1_Channel5, DISABLE);
// USART_ReceiveData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。我也不知道为啥!
UartReceiveLen = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度
// //***********帧数据处理函数************//
// printf ("The lenght:%d\r\n",UartReceiveLen);
// printf ("The data:\r\n");
// Usart1_Send(DMA_Rece_Buf,UartReceiveLen);
// printf ("\r\nOver! \r\n");
// //*************************************//
if(DMA_Rece_Buf[0]==0x02)
{
UartSendBuffer[0]=0X02;//固定通讯协议
UartSendBuffer[1]=0X36;
UartSendBuffer[2]=0X32;
UartSendBuffer[3]=0X36;
UartSendBuffer[4]=0X36;
UartSendBuffer[5]=0X03;
UartSendBuffer[6]=0X44;
UartSendBuffer[7]=0X37;
for(i=0;i<8;i++)
{
USART1->DR=UartSendBuffer[0];
while((USART1->SR&0X40)==0);//等待发送结束
}
}
if(DMA_Rece_Buf[0] == 0x05)
{
USART1->DR=ACK;
while((USART1->SR&0X40)==0);//等待发送结束
}
i = USART1->SR;
i = USART1->DR;
USART_ClearITPendingBit(USART1, USART_IT_IDLE); //清除中断标志
MYDMA_Enable(DMA1_Channel5); //恢复DMA指针,等待下一次的接收
}
}
2、看PLC和三菱编程软件的通信截图发现一个问题,接收到一帧数据和接收到一个字节好判断,但是怎么实现发送一帧数据 和发送一个字节的区别,看图中显示,是接收到软件发来的一帧数据,但是下位机回复的时候是一个字节一个字节的回复的,是不是要发送完一个字节后进行适量的延时来实现?求不吝赐教,谢谢、
|
最佳答案
查看完整内容[请看2#楼]
自问自答 结贴。研究了好几天,解决了这个问题。
1、关于通信协议,1位起始位 7位数据位 1位 偶校验 1位停止位 波特率9600这种奇葩的设置,STM32 的串口并不能直接设置,需要换一种思路来变相的达到要求。设置波特率 9600,8位数据位,偶校验,1位停止位。在接收和发送时忽略掉第8位数据,即在接收时 将数据与0x7f进行与运算,发送时 将数据与0x80进行或运算 再发出去,这样就能够正常通信。
html论坛里的一个帖子讲到过这件事情 ...
|