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