新手求教为什么串口接收数据总丢包
接收数据为:BB 97 11 30 00 11 22 33 44 55 66 77 88 99 00 11 22 FD 6F 03 1A 0D 0A
发送端一直不定时发此类数据
但是我用STM32F103RCT6单片机接收丢包挺多,丢包的频率很规律应该是我程序代码没写严谨,求大神指点
void Init_NVIC(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //定义一个NVIC向量表结构体变量
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断组 为2
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //配置串口1为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //设置占先优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //设置副优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口1中断
NVIC_Init(&NVIC_InitStructure); //根据参数初始化中断寄存器
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //配置串口1为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置占先优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置副优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口1中断
NVIC_Init(&NVIC_InitStructure); //根据参数初始化中断寄存器
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //配置串口1为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置占先优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //设置副优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口1中断
NVIC_Init(&NVIC_InitStructure); //根据参数初始化中断寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //配置串口1为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置占先优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置副优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能串口1中断
NVIC_Init(&NVIC_InitStructure); //根据参数初始化中断寄存器
}
void Init_Usart2(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO ,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 ,ENABLE);
//使能各个端口时钟,重要!!!
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //配置串口发送端口挂接到9端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用功能输出开漏
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置端口速度为50M
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIOA寄存器
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //接收
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入(复位状态);
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIOA寄存器
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
** 函数名称: Usart_Configuration
** 功能描述: 串口配置函数
** 参数描述: BaudRate设置波特率
** 作 者: Dream
** 日 期: 2011年6月20日
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
void Usart2_Configuration(uint32_t BaudRate)
{
USART_InitTypeDef USART_InitStructure; //定义一个串口结构体
USART_InitStructure.USART_BaudRate = BaudRate ; //波特率115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //传输过程中使用8位数据
USART_InitStructure.USART_StopBits = USART_StopBits_1; //在帧结尾传输1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No ; //奇偶失能
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流失能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //接收和发送模式
USART_Init(USART2, &USART_InitStructure); //根据参数初始化串口寄存器
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE); //使能串口中断接收
USART_Cmd(USART2, ENABLE); //使能串口外设
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
** 函数名称: USART1_IRQHandler
** 功能描述: 串口中断函数
** 参数描述: 无
** 作 者: Dream
** 日 期: 2011年6月20日
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
void USART2_IRQHandler()
{
int i=0;
u8 a=0;
extern u8 UART2_Save_data_box; //放置UART2接收到的字节需要溢出归0
extern u16 UART2_Save_data_box_pointer; //放置UART2接收到的字节盒子下一个数据放置的位置指向标志 需要溢出归0
extern u32 EPC_box;
extern u16 EPC_box_pointer;
extern u8 back_correct;
extern u32 error1;
extern u32 error2;
extern u32 error3;
extern u32 EPC_count_l;
extern u32 EPC_count_h;
extern u32 timer1;
extern u8 zisuo3;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //读取接收中断标志位USART_IT_RXNE
//USART_FLAG_RXNE:接收数据寄存器非空标志位
//1:忙状态0:空闲(没收到数据,等待。。。)
{
if(UART2_Save_data_box==0xBB) //判断数据包头
{
UART2_Save_data_box=USART_ReceiveData(USART2); //继续存储数据
UART2_Save_data_box_pointer++;
/*
if(UART2_Save_data_box==0x98&&UART2_Save_data_box==0x0D && UART2_Save_data_box==0x0A) //判断数据包尾
{
for(i=1;i<4;i++) //计算校验值
{
a+=(u8)UART2_Save_data_box;
}
if(a==UART2_Save_data_box) //校验成功
{
if(UART2_Save_data_box==0x01)
{
back_correct=1;
OUT2_LED=0;
}
else
{
back_correct=2;
}
}
for(i=0;i<UART2_Save_data_box_number;i++)
{
UART2_Save_data_box=0; //一旦判断到数据包的尾部则数组初始化
}
UART2_Save_data_box_pointer=1; //一旦判断到数据包的尾部则置1
}
else */if(UART2_Save_data_box==0x97&&UART2_Save_data_box==0x0D && UART2_Save_data_box==0x0A) //判断数据包尾
{
for(i=1;i<20;i++) //计算校验值
{
a+=(u8)UART2_Save_data_box;
}
if(a==UART2_Save_data_box) //校验成功
{
for(i=0;i<3;i++)
{
EPC_box=(UART2_Save_data_box<<24)+(UART2_Save_data_box<<16)+(UART2_Save_data_box<<8)+(UART2_Save_data_box<<0); //存储EPC
EPC_box_pointer++;
}
zisuo3=0;
OUT1_jingbao=1; //输出报警
timer1=0; //计时清0
EPC_count_l++; //标签总数+1
if(EPC_count_l>=1000000000)
{
EPC_count_l=0;
EPC_count_h++;
}
}
else
{
error1++; //偶然错误 错误标志加1
}
for(i=0;i<UART2_Save_data_box_number;i++)
{
UART2_Save_data_box=0; //一旦判断到数据包的尾部则数组初始化
}
UART2_Save_data_box_pointer=1; //一旦判断到数据包的尾部则置1
}
else if(UART2_Save_data_box_pointer>=23) //偶尔性的数据错误 开始清0
{
for(i=0;i<UART2_Save_data_box_number;i++)
{
UART2_Save_data_box=0;
}
UART2_Save_data_box_pointer=1;
error2++; //偶然错误 错误标志加1
}
if(EPC_box_pointer>=EPC_number)
{
EPC_box_pointer=0;
}
}
else if(UART2_Save_data_box==0x00) //如果上个数据不是数据包头
{
UART2_Save_data_box=USART_ReceiveData(USART2); //储存数据到UART2
}
else
{
error3++;
UART2_Save_data_box=USART_ReceiveData(USART2); //储存数据到UART2
}
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志位
}
}
数据包接收完UART2_Save_data_box_pointer应置0:) 是不是每次接收完没有清除标志位USART_IT_RXNE? 请添加一个超时复位 UART2_Save_data_box_pointer 的功能。
因为,当数据接收不够 23 组时,你的程序没有做处理。
导致 UART2_Save_data_box_pointer 一直累加到大于等于23组时,你的程序才做处理。 感觉楼主可以改下代码的结构,使用个万能的环形队列,中断只负责接收,数据放到主程序中进行解析,只要缓冲区内有完整的数据包就做相应的处理 丢包一般是时钟配置有点问题…… 串口传输一次性不能超过64个字节,多余的要做分包处理。 额,你的串口中断太复杂了,根本不能这样写中断,中断只能进去判断有无,有就放到一个fifo结构里,立即退出。外面程序空闲时来处理fifo里的数据流。
就是这么垃圾的中断代码居然也是抄别人的:
** 作 者: Dream
** 日 期: 2011年6月20日
语法上还是要尽量规范, 函数内 一般不提倡用extern ,可以通过包含头文件的形式搞定.
页:
[1]