(合同制定方法)单片机与上位机通信协议的制定
单片机和上位机通信协议的制定
单片机和上位机的串口通信协议分为上行协议和下行协议,要分别制定!上行协议,即由单片机向上位机发送数据。
下行协议,即由上位机向单片机发送数据。
而通信协议又要分固定长度和不定长度俩种
本文所介绍的协议属于简单的固定字长的通信协议!
下行协议由四个字节构成
上表是简单的上位机对单片机的控制指令
下述函数是C#中封装的串口通信类中的发送函数的封装publicvoidSerSendCommu(byteorderDef,bytedata)//参数1为命令字,参数二为要发送的数
//据,需要时可直接调用
{
Byte[]BSendTemp=newByte[SEND_LENTH];
BSendTemp[0]=PRE;
BSendTemp[1]=orderDef;
BSendTemp[2]=data;
BSendTemp[3]=END;
this.serialPort1.Write(BSendTemp,0,SEND_LENTH);
}
下位机中用中断方式接收字符,本文用的是GCC语言,下面是串口接收数据中断
ISR(USART_RXC_vect)//串口接收中断
{
unsignedcharstatus,data;
status=UCSRA;//**首先读取UCSRA的值,再读取UDR值,顺序不能颠倒,否则读取UDR后的UCSRA的
//值即会改变**
data=UDR;
if(!Uart_RecvFlag)//判断缓存中的数据是否读完,读完则接收指令
{
if((status&((1< { rx_buffer[rx_counter]=data; rx_counter++; switch(rx_counter) { case1: if(data!=USART_BEGIN_STX) rx_counter=0; break; case4: rx_counter=0; if(data==USART_END_STX) Uart_RecvFlag=1; break; } } } } 于单片机主循环程序的最前部分进行指令译码if(Uart_RecvFlag)//接收到命令 { switch(rx_buffer[1]) { case0xAA://单片机状态命令控制;ucWorkStatue=rx_buffer[2];//指令数据break; case0xDD://PWM值修改指令 OCR2=rx_buffer[2]; break; case0xFF://初始温度设定 break; } Uart_RecvFlag=0; } //随后进行执行指令 switch(ucWorkStatue) { case1://空闲模式 break; case2://测量模式,但不输出 break; case3://测量模式,由串口输出 break; case4://PWM输出测试 break; default: break; } 这样就能够利用串口对单片机进行于线命令控制了; 上行协议的制定! 和下行协议基本壹致! 于AVR单片机程序中定义了串口通信输出缓冲区,缓冲区的字长正好为协议的长度; //串口发送缓冲区变量声明 volatileunsignedchartx_buffer[TX_BUFFER_SIZE];//定义串口发送缓冲区volatileunsignedchartx_wr_index=0,tx_rd_index=0,tx_counter=0;//rx_wr_i ndex写指针,rx_rd_index读指针,rx_counter缓冲区数据个数 //USART发送函数 voidUSART_Transmit(unsignedchardata)//发送数据函数 { while(tx_counter==TX_BUFFER_SIZE);//输出缓冲区满,等待 asm("cli"); if(tx_counter||((UCSRA&DATA_REGISTER_EMPTY)==0)) { tx_buffer[tx_wr_index]=data; if(++tx_wr_index==TX_BUFFER_SIZE) tx_wr_index=0; ++tx_counter; } else UDR=data; asm("sei"); } //发送中断服务程序 ISR(USART_TXC_vect)//USART发送数据中断{ if(tx_counter) { --tx_counter; UDR=tx_buffer[tx_rd_index]; if(++tx_rd_index==TX_BUFFER_SIZE) { tx_rd_index=0; }