我現(xiàn)在正在研究基于avr,mega128的modbus 做了個modbus 也是基于網(wǎng)友的代碼調試的 上傳
Avr單片機中使用modbus協(xié)議的方法
有以下程序用gcc實現(xiàn),單片機用avr單片機。
ISR(USART0_RX_vect)//串口0接收中斷服務程序
{
volatile unsigned char status,data;
cli();//關中斷
status = UCSR0A;//ucsr0a賦值狀態(tài)標志
data = UDR0;//接收的數(shù)據(jù)放入data變量
usart0_rx_complete=0;//接收完成標志賦值0,還沒有完成
if ((status & (FRAMING_ERROR0 | PARITY_ERROR0 | DATA_OVERRUN0))==0)//如果各標志位正確則,執(zhí)行以下
{
usart0_rx_count++;//接收緩沖區(qū)指針加一
switch (usart0_rx_count)
{
case 1:
if(data==add//第一個字節(jié)是地址,讀入內部本機地址進行比較
{
usart0_rx_buf[0]=data;
TIMSK0=0x01;//啟動定時器0,進行超時控制
}
else
{
usart0_rx_count=0;
}
break;
case 2:
if (((data==0x03)||(data==0x01)||(data==0x05)||(data==0x10))==0)//如果第一位不等于讀指令0x03,01,05,10功能碼,則清接收緩沖區(qū)指針
{
usart0_rx_count=0;
}
else//等于這幾個功能碼則進行,則將他放入接收數(shù)組,并預計接收數(shù)組長度,不是10碼時都是8個字節(jié)
{
usart0_rx_buf[1]=data;
if (data!=0x10)
{
rx0_buf_size=8;
}
}
break;
case 3:
usart0_rx_buf[2]=data;
break;
case 4:
usart0_rx_buf[3]=data;
break;
case 5:
usart0_rx_buf[4]=data;
break;
case 6:
usart0_rx_buf[5]=data;
break;
case 7:
usart0_rx_buf[6]=data;//10碼時接收的字節(jié)計數(shù)
if (usart0_rx_buf[1]==0x10)
{
rx0_buf_size=9+usart0_rx_buf[6];
}
break;
case 8:
usart0_rx_buf[7]=data;//1,用10功能碼時有效的數(shù)據(jù)位,system_reg_data的數(shù)據(jù),這里規(guī)定最多接收26個字節(jié)(不帶crc)
break;
case 9:
usart0_rx_buf[8]=data;//2
break;
case 10:
usart0_rx_buf[9]=data;//3
break;
case 11:
usart0_rx_buf[10]=data;//4
break;
case 12:
usart0_rx_buf[11]=data;//5
break;
case 13:
usart0_rx_buf[12]=data;//6
break;
case 14:
usart0_rx_buf[13]=data;//7
break;
case 15:
usart0_rx_buf[14]=data;//8
break;
case 16:
usart0_rx_buf[15]=data;//9
break;
case 17:
usart0_rx_buf[16]=data;//10
break;
case 18:
usart0_rx_buf[17]=data;//11
break;
case 19:
usart0_rx_buf[18]=data;//12
break;
case 20:
usart0_rx_buf[19]=data;//13
break;
case 21:
usart0_rx_buf[20]=data;//14
break;
case 22:
usart0_rx_buf[21]=data;//15
break;
case 23:
usart0_rx_buf[22]=data;//16
break;
case 24:
usart0_rx_buf[23]=data;//17
break;
case 25:
usart0_rx_buf[24]=data;//18
break;
case 26:
usart0_rx_buf[25]=data;//19
break;
case 27:
usart0_rx_buf[26]=data;//20
break;
case 28:
usart0_rx_buf[27]=data;//21
break;
case 29:
usart0_rx_buf[28]=data;//22
break;
case 30:
usart0_rx_buf[29]=data;//23
break;
case 31:
usart0_rx_buf[30]=data;//24
break;
case 32:
usart0_rx_buf[31]=data;//25
break;
case 33:
usart0_rx_buf[32]=data;//26
break;
case 34:
usart0_rx_buf[33]=data;//27
break;
case 35:
usart0_rx_buf[34]=data;//28
break;
}
if(usart0_rx_count>=rx0_buf_size)//串口0接收到了指定個數(shù)的數(shù)組則
{
usart0_rx_count=0;//接收緩沖區(qū)指針清零
usart0_rx_complete=1;//串口0接收完標志
time0_num=0;//串口0的中斷次數(shù)清零。它是超時控制的依據(jù)
TIMSK0=0x00;//收到數(shù)據(jù)后則停止定時器0不進行超時控制
}
}
else
{
usart0_rx_count=0;
}
sei(); //開中斷
}
以上中斷接收程序可以實現(xiàn)上位機發(fā)來的0x03,01,05,10功能碼指令,并且可以自動判斷上位機發(fā)來10功能碼的包長。大家首先要深入了解modbus通訊協(xié)議的內涵,仔細體會各行程序的含義。其中本人加入了對通訊的超時控制,實際應用中很有必要。
前面已經(jīng)將上位機發(fā)來的命令,用中斷接收的方式存入了單片機的接收緩沖區(qū),中斷服務程序不能執(zhí)行太長時間,所以要將對指令的解讀放入了主程序里。
把對modbus指令的解讀程序列出,如下,只給出框架,因為每種應用是不一樣的,需自己加入。
void run_modbus(void)
{
switch (usart0_rx_buf[1])
{
//判斷主機發(fā)來的modbus 功能碼是什么
case 0x01://讀繼電器輸出的當前狀
要加入回傳數(shù)據(jù)
break;
case 0x03://功能碼03
要加入回傳數(shù)據(jù)
break;
case 0x05://05功能碼
要加入回傳數(shù)據(jù)
break;
case 0x10://10功能碼
要加入回傳數(shù)據(jù)
break;
}
}
以上程序完全依賴一個提供給上位機數(shù)據(jù)的數(shù)組,自己要仔細排列好數(shù)據(jù)順序,定義好長度。
|