|
我采用 ATMEAL 128单片机
(1)、定时中断时间间隔=10MS(CTC模式)
(2)、串口接收采用中断方式
(3)、串口发送采用中断方式
(4)、通讯协议采用MODBUS-RTU,
测试过程中:
上位机每隔1秒钟给单片机写51个(int)数据,通过MODBUS预置多个寄存器命令(功能码=16),但是上位机没有收到任何信息。
现象:
经跟踪单片机程序,单片机读取的数据帧的长度竟然是随机的,导致CRC校验通不过,因此单片机不给上位机回送应答信号。
也就是下段代码:
tempData = (USART1_mscomm_buffer[4]<<8) + USART1_mscomm_buffer[5]; //预置寄存器数量
tempData = tempData * 2;
tempData += 9; //预置寄存器数量*2+9=上位机数据帧的长度
奇怪的原因:
(1).我的定时中断服务程序大约需要0.8ms
(2).当我将定时中断服务程序中的大部分代码屏蔽后,单片机能够正确收到数据帧的长度。
(3).不屏蔽定时中断服务程序中的代码,而是每次只写2个(int)数据,单片机能够正确收到数据帧的长度。
void main(void)
{
unsigned int crcData;
unsigned int tempData;
//初始化省略
while (1)
{
USART1_Time_Proc();//超时处理(长时间没收到数据,将接收指针 USART1_receCount=0 )
if (USART1_receCount > 5)
{
switch (USART1_mscomm_buffer[1]) //分析功能码
{
case 16: //预置多个寄存器
tempData = (USART1_mscomm_buffer[4]<<8) + USART1_mscomm_buffer[5]; //预置寄存器数量
tempData = tempData * 2;
tempData += 9; //预置寄存器数量*2+9=上位机数据帧的长度
if (USART1_receCount >= tempData)
{
UCSR1B &= ~BIT(7);
if (USART1_mscomm_buffer[0] == module_addr))//比较设备地址
{
crcData = CRC16(USART1_mscomm_buffer,tempData-2); //计算CRC
//如果CRC校验通过
if (crcData == (USART1_mscomm_buffer[tempData-2]<<8)+ USART1_mscomm_buffer[tempData-1])
USART1_PresetMultipleRegisters();//调用预置多个寄存器子程序
}
USART1_receCount = 0; //接收指针清零
USART1_checkoutError = 0;
UCSR1B |= BIT(7);
}
break;
}
}
}
}
//接收中断
#pragma interrupt_handler USART1_RI_ISR:iv_USART1_RX
void USART1_RI_ISR(void)
{
unsigned char ch;
unsigned char status;
status = UCSR0A;
ch = UDR1;
if (USART1_receCount < MSCOMM_BUFFER_LENGTH)
USART1_mscomm_buffer[USART1_receCount++] = ch;
USART1_receTimeOut = 10; //超时计数单元
// 接收到一个字符后,如果100ms内未再次接收到数据,则将 USART1_receCount=0
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|