原来在Keil 3环境下选择AT89S8253作为器件,编写了一段程序。在Keil 环境下用纯软件仿真,判断逻辑都没有错。串口能够按照要求输出自己定义好的观测字符。 但是下载到AT89S8253以后,发现以下问题: 1.串口输出的第一个字符是正确的以后,后面接着所有字符都错误。 2. 必须在Small模式下编译,在Compact模式和Large模式下编译的程序都不允许,串口无任何字符输出。 --------------------- 我采取了以下措施,问题依旧: 1. 将串口波特率降低到9600。 2. 换掉目标板上的AT89S8253,重新焊接新的。 3. 将我程序中的“消息队列“相关函数去除,串口输出即可正确。 4. 换用陈明计老师的SmallRTOS的编写,软件仿真都正确,串口能够可以看到数据,但是下载之后无反应! 我的疑问: 1. 消息队列相关函数,我已经用Keil C里面纯软件仿真一步一步的调试过。逻辑没有问题!是否编译器参数设置问题? 2. 是否是软件代码问题?
我的编写的代码如下附件,请大家帮我找找原因!
#include "config_all.h" uint8 Uart_ReceFrame_State=0; //定义一个表示串口接收数据帧状态的变量,标明有没有接收到起始字符,帧长度,数据,校验字等状态
extern void Delay_50us(uint16 t); #define MCU_SerialInData_FIFO_MaxNumber 30 #define MCU_SerialOutData_FIFO_MaxNumber 30 #define System_Message_FIFO_MaxNumber 10
uint8 xdata MCU_SerialInData_FIFO[MCU_SerialInData_FIFO_MaxNumber]; //定义存储PDA下发下来的数据的数组,[0]为存储数组中有效数据的长度, uint8 xdata MCU_SerialOutData_FIFO[MCU_SerialOutData_FIFO_MaxNumber]; uint8 xdata System_Message_FIFO[System_Message_FIFO_MaxNumber];
uint8 xdata Uart1_Datain_buffer[30]; /*定义子串口1接收PDA命令缓冲存储数组*/ uint8 xdata Uart2_Datain_buffer[30]; /*定义子串口2接收PDA命令缓冲存储数组*/ uint8 xdata Uart3_Datain_buffer[30]; /*定义子串口3接收PDA命令缓冲存储数组*/ uint8 xdata Uart4_Datain_buffer[30]; /*定义子串口4接收PDA命令缓冲存储数组*/
uint8 Test_Stop=0; uint8 Have_Right_Frame=0;
#define All_Frame_data_number 40 uint8 xdata All_Frame_data[All_Frame_data_number]; //存储串口接收到得数据,保留的是一个完整的帧,方便以后计算 uint8 xdata PDA_Command[40]; //存储串口接收到得数据,保留的是一个完整的帧,方便以后计算 uint8 Frame_Data_number1,Frame_Data_number2; /*定义接收串口命令帧长度标识字符,通讯协议中的帧长度信息存入此变量*/ uint8 Frame_Data_Number_Flag; //定义帧数据字节的长度,准备在接受帧数据中作为计数器使用 uint8 CRC_16_Number; uint16 CRC_16_Result_Receiver; uint16 CRC_16_Result_Change;
uint8 xdata MCU_SerialPort_CanSend;
extern void VK3234_UartOut(uint8 xdata *Buf); /********************************************************************************************************* ** 函数名称: void InitSerial(void) ** 功能描述: 串口0初始化 ** 输 入: ** 输 出: ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/ void InitSerial(void) { SCON = 0x50; PCON = 0x00; //波特率加倍 TMOD = TMOD & 0x0f; TMOD = TMOD | 0x20; //工作于方式2,自动重装 TH1 = 0xfD; //串口通信的波特率是 9600 b/s TL1 = 0xfD;
//TH1=BAUDRATE; //TL1=BAUDRATE; TR1 = 1; ES = 1; }
/********************************************************************************************************* ** 函数名称: CreateMessagePool(uint8 xdata *Buf,uint8 SizeOfBuf) ** 功能描述: 建立一个环形的消息管理队列,并且进行初始化 ** 输 入: ** 输 出: ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/ uint8 CreateMessagePool(uint8 xdata *Buf,uint8 SizeOfBuf) { uint8 a=0xff; if((SizeOfBuf>4)&&(Buf!=NULL)) { Disable_MCU_Interrupt(); Buf[0]=0; //标识消息环中有用消息的个数; Buf[1]=SizeOfBuf; //标识消息队列最大可以存储多少个消息,Buf[1]以后固定不变,便于以后比较操作 Buf[2]=3; //存储真正存放有效消息的数组下标,指明哪一个数组值是要出消息对的 Buf[3]=0; //存放消息的的真正起始地址,这里存储第一个消息。 Enable_MCU_Interrupt(); a=Ture; } else { a=False; } return a; } /********************************************************************************************************* ** 函数名称: PostMessagePool(uint8 *Buf,uint8 Data) ** 功能描述: 将一个消息放入消息队列 ** 输 入: ** 输 出: ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------- ********************************************************************************************************/ uint8 PostMessagePool(uint8 xdata *Buf,uint8 data Data) { uint8 temp=0;
if(Buf==NULL) { return False; } Disable_MCU_Interrupt(); if(Buf[0]<(Buf[1]-3)) //判断消息队列中是否还有空间 { temp=Buf[2]+Buf[0]; //Buf[2]是当前第一个消息的存储位置+Buf[0]当前还有几个有效消息+1 if(temp>=Buf[1]) //判断存放的地址是否超过了消息最后一个存储位置(越界) { temp=temp-Buf[1]+3; //存储地址越界了,则存放在消息环的第一个位置,形成环形 } Buf[temp]=Data; //存储消息值 Buf[0]++; //标识消息环中有用消息的个数加1 Enable_MCU_Interrupt(); return Ture; } else { Enable_MCU_Interrupt(); return False; } } /********************************************************************************************************* ** 函数名称: uint8 PostMessagePool_Interrupt(uint8 *Buf,uint8 Data) ** 功能描述: 中断程序中使用,将一个消息放入消息队列, ** 输 入: ** 输 出: ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------- ********************************************************************************************************/ uint8 PostMessagePool_Interrupt(uint8 xdata *Buf,uint8 data Data) { uint8 temp=0;
if(Buf==NULL) { return False; } Disable_MCU_Interrupt(); if(Buf[0]<(Buf[1]-3)) //判断消息队列中是否还有空间 { temp=Buf[2]+Buf[0]; //Buf[2]是当前第一个消息的存储位置+Buf[0]当前还有几个有效消息+1 if(temp>=Buf[1]) //判断存放的地址是否超过了消息最后一个存储位置(越界) { temp=temp-Buf[1]+3; //存储地址越界了,则存放在消息环的第一个位置,形成环形 } Buf[temp]=Data; //存储消息值 Buf[0]++; //标识消息环中有用消息的个数加1 Enable_MCU_Interrupt(); return Ture; } else { Enable_MCU_Interrupt(); return False; } }
/********************************************************************************************************* ** 函数名称: GetMessagePool(uint8 *Buf,uint8 Data) ** 功能描述: 从指定的消息队列取出一个消息 ** 输 入: ** 输 出: 调用成功,返回Ture,调用失败返回False ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------- ********************************************************************************************************/ uint8 GetMessagePool(uint8 xdata *Buf,uint8 data *Data) {
if(Buf==NULL) { return False; } Disable_MCU_Interrupt(); if(Buf[0]!=0) {
*Data=Buf[Buf[2]];
Buf[0]--; //标识消息环中有用消息的个数减1 Buf[2]++; //出对的消息指针加1,指向下一个消息 if(Buf[2]>=Buf[1]) { Buf[2]=3;
} Enable_MCU_Interrupt(); return Ture; } else { Enable_MCU_Interrupt(); return False; } }
/********************************************************************************************************* ** 函数名称:uint8 GetMessageNumber(uint8 *Buf) ** 功能描述: 查询消息队列的消息个数 ** 输 入: ** 输 出: 返回消息个数 ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------- ********************************************************************************************************/ uint8 GetMessageNumber(uint8 xdata *Buf) { uint8 temp; if(Buf==NULL) { return False; }
if(Buf[0]!=0) { temp=Buf[0]; Enable_MCU_Interrupt(); return temp; } else {
return 0; } }
/********************************************************************************************************* ** 函数名称:uint8 ClearMessagePool(uint8 *Buf) ** 功能描述: 清空消息队列 ** 输 入: ** 输 出: 返回消息个数 ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------- ********************************************************************************************************/ uint8 ClearMessagePool(uint8 xdata *Buf) { if(Buf==NULL) { return False; }
Buf[0]=0; //标识消息环中有用消息的个数; // Buf[1]=SizeOfBuf; //标识消息队列最大可以存储多少个消息,Buf[1]以后固定不变,便于以后比较操作 Buf[2]=3; //存储真正存放有效消息的数组下标,指明哪一个数组值是要出消息对的 Buf[3]=0; //存放消息的的真正起始地址,这里存储第一个消息。 return Ture; }
/********************************************************************************************************* ** 函数名称: PutChar ** 功能描述: 发送一个字节 ** 输 入: Data:发送的数据 ** 输 出: 无 ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/ void PutChar(uint8 data Data) { Disable_MCU_Interrupt(); if (MCU_SerialPort_CanSend == Ture) { MCU_SerialPort_CanSend = False; SBUF = Data; /* 串口空闲,直接发送 */ } else { PostMessagePool(MCU_SerialOutData_FIFO,Data);; /* 数据入队 */ } Enable_MCU_Interrupt(); }
/********************************************************************************************************* ** 函数名称: comm ** 功能描述: 串口中断处理程序 ** 输 入: 无 ** 输 出: 无 ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年3月12日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/
void comm(void) interrupt 4 { uint8 data temp; // uint8 data temp1; EA=0; if (RI == 1) //这句适用于普通C51单片机 { RI = 0; temp=SBUF; PostMessagePool_Interrupt(MCU_SerialInData_FIFO,temp);
} if (TI == 1) { TI = 0; // if(GetMessageNumber(MCU_SerialOutData_FIFO)!=False) //如果串口接收缓冲区有数据 // { // if( GetMessagePool(MCU_SerialOutData_FIFO,&temp1)==Ture) // { // SBUF=temp1; // } // } //else //{ // MCU_SerialPort_CanSend=Ture; // } } EA=1; return;
} /*********************************************************************************************************; ** 函数名称: uint8 Frame_DataLengthNumber_ChangeFromat2(uint8 a1, uint8 a2) ** 功能描述: 解析上位机发送的命令中帧长度字符代表的长度 ** 输 入: 帧长度字符1和帧长度字符2 ** 输 出: 帧长度 ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年5月3日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/
void Frame_DataLengthNumber_ChangeFromat2(void)
{ if((Frame_Data_number1>=0)&&(Frame_Data_number1<10)) { Frame_Data_number1= Frame_Data_number1+Frame_Data_number1+Frame_Data_number1+Frame_Data_number1+Frame_Data_number1+ Frame_Data_number1+Frame_Data_number1+Frame_Data_number1+Frame_Data_number1+Frame_Data_number1;
} Frame_Data_number2=Frame_Data_number1+Frame_Data_number2; //return Frame_Data_number2; }
/*********************************************************************************************************; ** 函数名称: uint16 cal_crc(uint8 cHar *ptr, uint8 len) ** 功能描述: 计算CRC16的算法 ** 输 入: 计算字符串地址,字符长度 ** 输 出: CRC16计算结果 ** 全局变量: 无 ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年5月3日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/
uint16 Cal_CRC(uint8 xdata *ptr, uint8 len) { uint8 i; uint16 crc_value =0; while(len--) { for(i=0x80; i!=0; i>>=1 ) { if (crc_value&0x8000) crc_value = (crc_value << 1) ^0x8005 ; else crc_value = crc_value << 1 ; if(*ptr&i) crc_value^=0x8005 ; } ptr++; } return(crc_value); }
/*********************************************************************************************************; ** 函数名称: uint8 Faylse_Uart_Frame(uint8 Data) ** 功能描述: 串口接收帧数据帧分析 ** 输 入: ** 输 出: ** 全局变量: ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年5月3日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/
void Faylse_Uart_Frame(void) { uint8 temp;
for(temp=0;temp<40;temp++) { PDA_Command[temp]=0; //PDA_Command[0]包含了命令字1个字节的长度+ 真正有效数据的长度 } PDA_Command[0]=Frame_Data_number2; //PDA_Command[0]保存着帧数据长度,这长度包含了转义字符的长度,实际使用的时候要转换 if(All_Frame_data[3]==1) //数据发往子串口1 { PDA_Command[1]=1; } else if(All_Frame_data[3]==2) //数据发往子串口2 { PDA_Command[1]=2; } else if(All_Frame_data[3]==3) //数据发往子串口3 { PDA_Command[1]=3; } else if(All_Frame_data[3]==4) //数据发往子串口4 { PDA_Command[1]=4; } for(temp=0;temp<Frame_Data_number2-1;temp++) //取出缓冲数组的值,并且分析专业字符,重新计算字节的长度 { if(All_Frame_data[3+2+temp]==Uart_ReceFrame_StartByte2) { if(All_Frame_data[3+2+1+temp]==Uart_ReceFrame_StartByte2) { PDA_Command[temp+2]=0x56; PDA_Command[0]--; temp++; } else if(All_Frame_data[3+2+1+temp]==Uart_ReceFrame_StartByte3) { PDA_Command[temp+2]=0x57; PDA_Command[0]--; temp++; } } else { PDA_Command[temp+2]=All_Frame_data[3+1+temp]; } } PDA_Command[0]--; //减去命令字节的1个字节长度,剩下数值只表示要发送到串口数据的字节数 }
/*********************************************************************************************************; ** 函数名称: void Detet_Receiver() ** 功能描述: 检测串口状态,等待接收到一个完整的有效的帧,发送消息到系统消息队列 ** 输 入: ** 输 出: ** 全局变量: ** 调用模块: 无 ** ** 作 者: LXJ ** 日 期: 2009年5月3日 **------------------------------------------------------------------------------------------------------- ** 修改人: ** 日 期: **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/ void Detet_Receiver() {
uint8 data temp1;
uint16 CRC_Result_temp=0;
if(GetMessageNumber(MCU_SerialInData_FIFO)!=False) //如果串口接收缓冲区有数据 { if( GetMessagePool(MCU_SerialInData_FIFO,&temp1)==Ture) //假如取值成功 { switch(Uart_ReceFrame_State) { case Uart_Dete_Frame_InitState: if(temp1==Uart_ReceFrame_StartByte1) //判断是否是帧起始字符0x55 { Uart_ReceFrame_State=Uart_Dete_Frame_StartByte_End;//标明串口已经接收到帧起始字符 All_Frame_data[0]=0x55; //存储帧起始字符 } else { Uart_ReceFrame_State=Uart_Dete_Frame_InitState; Frame_Data_Number_Flag=0; Frame_Data_number2=0; }
break; case Uart_Dete_Frame_StartByte_End: { Frame_Data_number1=temp1; All_Frame_data[1]=Frame_Data_number1; Uart_ReceFrame_State=Uart_Dete_Frame_LengthByte1_End;//标明串口已经接收到帧长度的第一个字符
} break; case Uart_Dete_Frame_LengthByte1_End: { Frame_Data_number2=temp1; All_Frame_data[2]=Frame_Data_number2; Frame_DataLengthNumber_ChangeFromat2(); if(Frame_Data_number2>99)/*通讯协议的帧长度字符超出了所定义的最大长度*/ { /***************************************** 这里发送数据帧长度出错的信息个PDA *****************************************/ ClearMessagePool(MCU_SerialInData_FIFO); /*清空串口输入消息队列*/ All_Frame_data[0]=0; All_Frame_data[1]=0; All_Frame_data[2]=0; //OSQPost(CommandData, Frame_Length_Wrong);/*发送串口出错消息到主程序处理*/ Uart_ReceFrame_State=Uart_Dete_Frame_InitState; } else /*通讯协议的帧长度字符没有超出了所定义的最大长度*/ { PDA_Command[0]=Frame_Data_number2; //将串口帧数据长度放入PDA_Command[0] } Uart_ReceFrame_State=Uart_Dete_Frame_LengthByte2_End;//标明串口已经接收到帧长度的第二个字符 } break; case Uart_Dete_Frame_LengthByte2_End: { if((temp1>0)&&(temp1<5)) { PDA_Command[1]=temp1; /*将传输数据帧中的指令类型字节放入数组的第二个字节,标明数据是发往哪个子串口的*/ All_Frame_data[3]=temp1; /*整理帧数据第四个字节,便于计算CRC*/ Uart_ReceFrame_State=Uart_Dete_Frame_OrdeTyte_End;//标明串口已经接收到帧长度的命令类型字符 Frame_Data_Number_Flag++; } else { ClearMessagePool(MCU_SerialInData_FIFO); /*清空串口输入消息队列*/ All_Frame_data[0]=0; All_Frame_data[1]=0; All_Frame_data[2]=0; //OSQPost(CommandData, Frame_Length_Wrong);/*发送串口出错消息到主程序处理*/ Frame_Data_Number_Flag=0; Uart_ReceFrame_State=Uart_Dete_Frame_InitState; } } break; case Uart_Dete_Frame_OrdeTyte_End: { if((Uart_ReceFrame_State==Uart_Dete_Frame_OrdeTyte_End)&&(Frame_Data_Number_Flag<Frame_Data_number2)) { All_Frame_data[3+Frame_Data_Number_Flag]= temp1; //存入All_Frame_data[]准备计算CRC Frame_Data_Number_Flag++; //接收到数据变量加1 } if(Frame_Data_Number_Flag==Frame_Data_number2) { Uart_ReceFrame_State=Uart_Dete_Frame_DataByte_End; } } break; case Uart_Dete_Frame_DataByte_End: { if(CRC_16_Number==0) { CRC_16_Result_Receiver=temp1; All_Frame_data[Frame_Data_Number_Flag+3]=temp1; CRC_16_Result_Receiver=CRC_16_Result_Receiver<<8; CRC_16_Number=1;   |