|
总线静止时间:MODBUS_RTU协议规定发送数据前要求数据总线静止时间即无数据发送时间大于5ms (波特率为9600时)。大约是发送4个字节的时间。
本代码使用一个定时器设定定时时间是5.1ms,当收到第一个数据后清零计时器,之后没收到一个字节就清零一次定时器。如果定时器溢出就认定收到一个完整的数据报。
//************************************************
// 定时器 t2 5.1ms
// 定时器溢出则标志收到一个完整数据帧
//全局变量 usart1_rx_t_f 串口接收状态标志
// usart1_f 数据区有效标志
//************************************************
#pragma interrupt_handler timer2_ovf_isr:11
void timer2_ovf_isr(void)
{
TCNT2 = 0x6b; //重装计数器
if(usart1_rx_t_f==0)//不是接收状态 返回
return;
usart1_f=1; //标志缓冲区数据有效 防止数据错误
usart1_rx_t_f=0;//清零接收标志 防止再次中断进入t2中断
SEI();
modbus_cl(usart1_rx_sp); //调用处理函数
usart1_f=0;//释放缓冲区
}
//******************************************************************
//**********************************************
// 串口1接收
//全局变量 : usart1_rx_buffer 串口接收缓冲区 150字节
// usart1_rx_sp 接收缓冲区指针
// usart1_f 是1 接收缓冲区数据未处理
// usart1_rx_t_f 是 1标志开始接收数据
//
//**********************************************
#pragma interrupt_handler uart1_rx_isr:31
void uart1_rx_isr(void)
{
unsigned char temp,temp_rx;
temp=UCSR1A; //读取状态标志
temp_rx=UDR1;//读取数据
SEI(); //开中断
TCNT2 = 0x6b;//重新计时
if(temp&((1<<FE1)|(1<<UPE1))) //检验失败 帧错误
{
usart1_rx_t_f=0;//字节出错 结束接收状态
return;
}
if(usart1_f==1)//缓冲区数据未处理
{
return;
}
if(usart1_rx_t_f==0)//数据帧开始接收
{
usart1_rx_sp=0; //指针清零
usart1_rx_t_f=1;//标志进入接收状态
usart1_rx_buffer[0]=temp_rx;//保存第一个数
}
else
{
usart1_rx_buffer[usart1_rx_sp]=temp_rx; //保存数据
}
usart1_rx_sp++; //缓冲区指针自加
if(usart1_rx_sp>149)//防止缓冲区溢出
{
usart1_rx_sp=0; //溢出清零指针
usart1_rx_t_f=0; //结束接收状态
}
}
//********************************* |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|