本軟件可分為以下五個部分,第一部分是狀態(tài)設(shè)定和位置監(jiān)測模塊,其中發(fā)電車的行車和發(fā)電狀態(tài)的設(shè)定是由一個船型開關(guān)決定的,當(dāng)開關(guān)閉合時,為發(fā)電狀態(tài),反之為行車狀態(tài),步進(jìn)電機(jī)控制油門的開合,但考慮到異常情況,用一個常開型開關(guān)實時監(jiān)測步進(jìn)電機(jī)是否轉(zhuǎn)動到了極限位置;第二部分為LCD液晶顯示,主要將串口通信得到的發(fā)電機(jī)輸出電的頻率fre、發(fā)電機(jī)輸出電的電流current以及控制步進(jìn)電機(jī)轉(zhuǎn)動快慢的方波頻率mtfre這三個參數(shù)實時顯示在LCD液晶上。第三部分為單片機(jī)與發(fā)電機(jī)上的儀表之間的Modbus-RTU串口通信,通過軟件的實時發(fā)送和接收可以得到發(fā)電機(jī)輸出電的頻率和電流等參數(shù);第四部分為利用定時中斷實現(xiàn)頻率可調(diào)的方波輸出,根據(jù)發(fā)電機(jī)的頻率與額定頻率50HZ的比較來決定輸出方波的頻率,而方波的頻率之所以可以實時變化的原因是通過改變定時器的初值來實現(xiàn)的,改變了定時器的初值,則改變了定時時間的大小,在每一次溢出中斷產(chǎn)生時,置反某一個I/O口的電平,從而實現(xiàn)了頻率可調(diào)的方波輸出;第五部分是步進(jìn)電機(jī)的控制模塊,這里需要了解步進(jìn)電機(jī)的工作原理以及驅(qū)動原理,這個系統(tǒng)采用專用驅(qū)動器驅(qū)動步進(jìn)電機(jī)進(jìn)行轉(zhuǎn)動,驅(qū)動器上的輸入信號包括脈沖信號、方向信號和使能信號,只要將這三種信號按照要求進(jìn)行輸入,驅(qū)動器就可以控制步進(jìn)電機(jī)進(jìn)行正常轉(zhuǎn)動; 整體的軟件功能是在幾個模塊函數(shù)的相互聯(lián)系相互調(diào)用的情況下實現(xiàn)的,每一個模塊有自己的專用函數(shù),在編寫程序時,用特殊的專用的函數(shù)名來對各個模塊的函數(shù)進(jìn)行命名,這樣方便查找和修改。 我覺得大家感興趣的應(yīng)該是MODBUS通信,因為用到這種通信的一般是工業(yè)儀器儀表,所以我想給大家介紹一下,我在編寫這一塊時的問題和解決辦法。 1. Modbus-RTU串口通信模塊通信協(xié)議:該模塊是整個軟件的重點部分,實現(xiàn)發(fā)電車上的電力儀表與單片機(jī)之間的實時通信,得到系統(tǒng)所要提取的發(fā)電機(jī)的頻率和電流。Modbus協(xié)議是應(yīng)用于電子控制器上的一種通用語言。通過此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)和其它設(shè)備之間可以通信。發(fā)電機(jī)上的電力儀表本身規(guī)定用的通信協(xié)議為RS485接口Modbus-RTU通信協(xié)議。當(dāng)在Modbus網(wǎng)絡(luò)上通信時,此協(xié)議決定了每個控制器必須要知道它們的設(shè)備地址,識別按地址發(fā)來的消息,決定要產(chǎn)生何種行為。如果需要回應(yīng),控制器將生成反饋信息并通過Modbus協(xié)議發(fā)送。 在Modbus協(xié)議中,典型的主設(shè)備可以為:主機(jī)和可編程儀表。典型的從設(shè)備主要為:可編程控制器。在系統(tǒng)中,單片機(jī)為主設(shè)備,發(fā)電機(jī)上的電力儀表為從設(shè)備。主設(shè)備可單獨和從設(shè)備通信,也能以廣播方式和所有從設(shè)備通信,如果單獨通信,從設(shè)備返回一消息作為回應(yīng),如果是以廣播方式查詢的,則從設(shè)備們不作任何回應(yīng)。Modbus協(xié)議建立了主設(shè)備查詢的格式:設(shè)備(或廣播)地址、功能代碼、所有要發(fā)送的數(shù)據(jù)、一錯誤檢測域。從設(shè)備回應(yīng)消息也由Modbus協(xié)議構(gòu)成,包括要確認(rèn)行動的域、任何要返回的數(shù)據(jù)、和一錯誤檢測域。如果在消息接收過程中發(fā)生一錯誤,或從設(shè)備不能執(zhí)行其命令,從設(shè)備將建立一錯誤消息并把它作為回應(yīng)發(fā)送出去。 (1)查詢 查詢消息中的功能代碼告之被選中的從設(shè)備要執(zhí)行何種功能。數(shù)據(jù)段包含了從設(shè)備要執(zhí)行功能的任何附加信息。例如功能代碼03是要求從設(shè)備讀保持寄存器并返回它們的內(nèi)容。數(shù)據(jù)段必須包含要告之從設(shè)備的信息:從何寄存器開始讀及要讀的寄存器數(shù)量。錯誤檢測域為從設(shè)備提供了一種驗證消息內(nèi)容是否正確的方法。 查詢數(shù)據(jù)包結(jié)構(gòu)如下: 從機(jī) 地址 | | | | 數(shù)據(jù)字節(jié)長度高字節(jié) | 數(shù)據(jù)字節(jié)長度低字節(jié) | | |
(2)回應(yīng) 如果從設(shè)備產(chǎn)生一正常的回應(yīng),在回應(yīng)消息中的功能代碼是在查詢消息中的功能代碼的回應(yīng)。數(shù)據(jù)段包括了從設(shè)備收集的數(shù)據(jù):像寄存器值或狀態(tài)。如果有錯誤發(fā)生,功能代碼將被修改以用于指出回應(yīng)消息是錯誤的,同時數(shù)據(jù)段包含了描述此錯誤信息的代碼。錯誤檢測域允許主設(shè)備確認(rèn)消息內(nèi)容是否可用。 回應(yīng)數(shù)據(jù)包結(jié)構(gòu): (3)兩種傳輸方式 控制器能設(shè)置為兩種傳輸模式:ASCII或RTU中的任何一種在標(biāo)準(zhǔn)的Modbus網(wǎng)絡(luò)通信。用戶選擇想要的模式,包括串口通信參數(shù)(波特率、校驗方式等),在配置每個控制器的時候,在一個Modbus網(wǎng)絡(luò)上的所有設(shè)備都必須選擇相同的傳輸模式和串口參數(shù)。相對來說,RTU模式傳輸效率更高,因此,在當(dāng)前普遍的生產(chǎn)環(huán)境中RTU模式獲得了廣泛應(yīng)用,而ASCII模式只作為特殊情況下的可選項。 ASCII模式 當(dāng)控制器設(shè)為在Modbus網(wǎng)絡(luò)上以ASCII(美國標(biāo)準(zhǔn)信息交換代碼)模式通信,一個信息中的每8個比特作為2個ASCII字符傳輸,如數(shù)值63H用ASCII方式時,需發(fā)送兩個字節(jié),即ASCII“6"(0110110)和ASCII”3“(0110011),ASCII字符占用的位數(shù)有7位和8位,國際通用7位為多。這種方式的主要優(yōu)點是字符發(fā)送的時間間隔可達(dá)到1秒而不產(chǎn)生錯誤。 代碼系統(tǒng) · 十六進(jìn)制,ASCII字符0...9,A...F · 消息中的每個ASCII字符都是一個十六進(jìn)制字符組成 每個字節(jié)的位 · 1個起始位 · 7個數(shù)據(jù)位,最小的有效位先發(fā)送 · 1個奇偶校驗位,無校驗則無 1個停止位(有校驗時),2個Bit(無校驗時) 錯誤檢測域 · LRC(縱向冗長檢測) RTU模式 當(dāng)控制器設(shè)為在Modbus網(wǎng)絡(luò)上以RTU模式通信,在消息中的每個8Bit字節(jié)按照原值傳送,不做處理,如63H,RTU將直接發(fā)送01100011。這種方式的主要優(yōu)點是:數(shù)據(jù)幀傳送之間沒有間隔,相同波特率下傳輸數(shù)據(jù)的密度要比ASCII高,傳輸速度更快。 代碼系統(tǒng) 8位二進(jìn)制,十六進(jìn)制數(shù)0...9,A...F 消息中的每個8位域都是一或兩個十六進(jìn)制字符組成 每個字節(jié)的位 1個起始位 8個數(shù)據(jù)位,最小的有效位先發(fā)送 1個奇偶校驗位,無校驗則無 1個停止位(有校驗時),2個Bit(無校驗時) (4)數(shù)據(jù)校驗方式 CRC校驗 CRC域是兩個字節(jié),包含一16位的二進(jìn)制值。它由傳輸設(shè)備計算后加入到消息中。接收設(shè)備重新計算收到消息的CRC,并與接收到的CRC域中的值比較,如果兩值不同,則有誤。 CRC是先調(diào)入一值是全“1”的16位寄存器,然后調(diào)用一過程將消息中連續(xù)的8位字節(jié)和當(dāng)前寄存器中的值進(jìn)行處理。僅每個字符中的8Bit數(shù)據(jù)對CRC有效,起始位和停止位以及奇偶校驗位均無效。 CRC產(chǎn)生過程中,每個8位字符都單獨和寄存器內(nèi)容相異或(XOR),結(jié)果向最低有效位方向移動,最高有效位以0填充。LSB被提取出來檢測,如果LSB為1,寄存器單獨和預(yù)置的值或一下,如果LSB為0,則不進(jìn)行。整個過程要重復(fù)8次。在最后一位(第8位)完成后,下一個8位字節(jié)又單獨和寄存器的當(dāng)前值相異或(XOR)。最終寄存器中的值,是消息中所有的字節(jié)都執(zhí)行之后的CRC值。 CRC添加到消息中時,低字節(jié)先加入,然后高字節(jié)。 CRC-16錯誤校驗程序如下:報文(此處只涉及數(shù)據(jù)位,不指起始位、停止位和任選的奇偶校驗位)被看作是一個連續(xù)的二進(jìn)制,其最高有效位(MSB)首選發(fā)送。報文先與X↑16相乘(左移16位),然后看X↑16+X↑15+X↑2+1除,X↑16+X↑15+X↑2+1可以表示為二進(jìn)制數(shù)11000,0000,0000,0101。整數(shù)商位忽略不記,16位余數(shù)加入該報文(MSB先發(fā)送),成為2個CRC校驗字節(jié)。余數(shù)中的1全部初始化,以免所有的零成為一條報文被接收。經(jīng)上述處理而含有CRC字節(jié)的報文,若無錯誤,到接收設(shè)備后再被同一多項式(X↑16+X↑15+X↑2+1)除,會得到一個零余數(shù)(接收設(shè)備核驗這個CRC字節(jié),并將其與被傳送的CRC比較)。全部運算以2為模(無進(jìn)位)。 習(xí)慣于成串發(fā)送數(shù)據(jù)的設(shè)備會首選送出字符的最右位(LSB-最低有效位)。而在生成CRC情況下,發(fā)送首位應(yīng)是被除數(shù)的最高有效位MSB。由于在運算中不用進(jìn)位,為便于操作起見,計算CRC時設(shè)MSB在最右位。生成多項式的位序也必須反過來,以保持一致。多項式的MSB略去不記,因其只對商有影響而不影響余數(shù)。 LRC檢驗 LRC錯誤校驗用于ASCII模式。這個錯誤校驗是一個8位二進(jìn)制數(shù),可作為2個ASCII十六進(jìn)制字節(jié)傳送。把十六進(jìn)制字符轉(zhuǎn)換成二進(jìn)制,加上無循環(huán)進(jìn)位的二進(jìn)制字符和二進(jìn)制補碼結(jié)果生成LRC錯誤校驗(參見圖)。這個LRC在接收設(shè)備進(jìn)行核驗,并與被傳送的LRC進(jìn)行比較,冒號(:)、回車符號(CR)、換行字符(LF)和置入的其他任何非ASCII十六進(jìn)制字符在運算時忽略不計。 (5)Modbus協(xié)議中功能碼定義 Modbus功能碼在查詢數(shù)據(jù)包和回應(yīng)數(shù)據(jù)包里都只占用一個字節(jié),取值范圍是1~127。之所以127以上不能使用,是因為Modbus規(guī)定當(dāng)通信出現(xiàn)異常時,功能碼+0X80(十進(jìn)制128)代表異常狀態(tài),因此129~255的取值代表異常碼。 Modbus相關(guān)公共功能碼: 函數(shù)說明:在了解了Modbus協(xié)議之后,開始編寫Modbus-RTU通信函數(shù)。本系統(tǒng)所用的PIC18F4520單片機(jī)最小系統(tǒng)只有RS232通信接口,電力儀表提供的是串行異步半雙工的RS485通信接口,故需用RS232轉(zhuǎn)RS485轉(zhuǎn)接器實現(xiàn)通信。本模塊用USART來編寫通信函數(shù),且必須將其設(shè)置為串行異步半雙工的通信方式,相關(guān)USART初始化函數(shù)如下: //USART模塊初始化
void USARTinit(void)
{
TXSTAbits.SYNC=0; //選擇異步通信方式
TXSTAbits.TX9=0; //選擇8位發(fā)送數(shù)據(jù)格式
//TXSTAbits.TXEN=1; //允許發(fā)送,配置為半雙工方式
RCSTAbits.SPEN=1; //使能串口
RCSTAbits.RX9=0; //選擇8位接收數(shù)據(jù)模式
//RCSTAbits.CREN=1; //異位模式下,使能接收器
BAUDCONbits.BRG16=1; //使能16位的波特率發(fā)生器
TXSTAbits.BRGH=1; //采用高速波特率
SPBRGH=832/256;
SPBRG=832%256; //波特率設(shè)置為9600,系統(tǒng)時鐘為32MHZ
} 在這個函數(shù)模塊中,電力儀表要收到來自單片機(jī)的查詢數(shù)據(jù)包以后,會返回一個回應(yīng)數(shù)據(jù)包,而且由于已知要查的頻率變量在儀表的74、75兩個寄存器以內(nèi),發(fā)送數(shù)據(jù)包一共有8個字節(jié),回應(yīng)數(shù)據(jù)包一共有9個字節(jié),本來需要根據(jù)兩個字節(jié)之間的傳輸時間是否大于3.5個字節(jié)傳輸時間來確定是否為新的數(shù)據(jù)包,但在已知回應(yīng)數(shù)據(jù)包字節(jié)數(shù)的情況下,軟件可以簡化為直接判斷單片機(jī)接收到的回應(yīng)數(shù)據(jù)包的字節(jié)數(shù)是否為9。按照這個思路,我們可以打開單片機(jī)UASRT的接收中斷,首先,將通信方式配置為發(fā)送模式,在單片機(jī)將查詢數(shù)據(jù)包發(fā)送給電力儀表后,將通信方式配置為接收模式,電力儀表發(fā)送給單片機(jī)一個字節(jié),則接收中斷標(biāo)志位置1,我們將接收到的字節(jié)存儲在接收數(shù)組里面,通過相關(guān)函數(shù)將接收數(shù)組里面有效的信息提取出來加以使用。 接收中斷相關(guān)函數(shù)如下: void USARTINT(void)
{
RCONbits.IPEN=0; //禁止中斷嵌套,禁止中斷優(yōu)先級功能,所以這里不用加上低優(yōu)先級中斷服務(wù)函數(shù),但加上問題不大
INTCON|=0XC0; //CPU開中斷,開啟了總中斷GIE和外設(shè)中斷PEIE,即允許外設(shè)中斷 IPR1bits.RCIP=0; //設(shè)置禁止EUSART接收中斷為高優(yōu)先級
PIR1bits.RCIF=0; //清USART接收中斷標(biāo)志
PIE1bits.RCIE=1; //允許USART接收中斷
}
#pragma interrupt PIC18F_HIGH_ISR
void PIC18F_HIGH_ISR(void)
{
if(1==PIR1bits.RCIF) //rx_index為接收數(shù)組的長度
{
flag=0;
PIR1bits.RCIF=0; //清除接收中斷標(biāo)志位
if(rx_index<sizeof(rx_buf)) //接收緩沖器尚未用完
{
rx_buf[rx_index]=RCREG;
rx_index++; //將接收到的數(shù)據(jù)存進(jìn)接收數(shù)組,并遞增計數(shù)器rx_index
}
if(rx_index==9) //接收到九個字節(jié),說明一幀結(jié)束
{ rx_index=0;flag=1;} //接受到完整的一幀數(shù)據(jù)
} } 該模塊發(fā)送函數(shù)的設(shè)計過程為構(gòu)建有效信息發(fā)送數(shù)組,根據(jù)發(fā)送數(shù)組計算CRC校驗碼,最后將有效信息和CRC校驗碼構(gòu)造成一個完整的發(fā)送數(shù)組再一并發(fā)送出去。在這個過程中,比較重要的為CRC計算函數(shù),因為有效信息在已知電力儀表相關(guān)寄存器信息以后是確定的,但若校驗碼錯誤,即使單片機(jī)將發(fā)送數(shù)組發(fā)送給電力儀表,電力儀表經(jīng)過計算以后與單片機(jī)發(fā)送過來的CRC校驗碼不相等,電力儀表則判斷為發(fā)送信息錯誤,會發(fā)送異常碼給單片機(jī),這樣通信為不成功,故以下著重介紹CRC計算函數(shù): //CRC檢驗函數(shù) 1 unsigned short crc(unsigned char *ptr,unsigned char size) { unsigned short a,b,tmp,CRC16,V; CRC16=0xffff; //CRC寄存器初始值 for (a=0;a<size;a++) //N個字節(jié) { CRC16=*ptr^CRC16; for (b=0;b<8;b++) //8位數(shù)據(jù) { tmp=CRC16 & 0x0001; CRC16 =CRC16 >>1; //右移一位 if (tmp) CRC16=CRC16 ^ 0xa001; //異或多項式 } *ptr++; } V = ((CRC16 & 0x00FF) << 8) | ((CRC16 & 0xFF00) >> 8); //高低字節(jié)轉(zhuǎn)換,這個時候低字節(jié)在高八位,高字節(jié)在低八位 return V; } 生成CRC-16校驗字節(jié)的步驟如下: ①例如一個16位寄存器,所有數(shù)位均為1。 ②該16位寄存器的高位字節(jié)與開始8位字節(jié)進(jìn)行“異或”運算。運算結(jié)果放入這個16位寄存器。 ③把這個16寄存器向右移一位。 ④若向右(標(biāo)記位)移出的數(shù)位是1,則生成多項式10,1000,000,0000,001和這個寄存器進(jìn)行“異或”運算;若向右移出的數(shù)位是0,則返回③。 ⑤重復(fù)③和④,直至移出8位。 ⑥另外8位與該十六位寄存器進(jìn)行“異或”運算。 ⑦重復(fù)③~⑥,直至該報文所有字節(jié)均與16位寄存器進(jìn)行“異或”運算,并移位8次。 ⑧這個16位寄存器的內(nèi)容即2字節(jié)CRC錯誤校驗,被加到報文的最高有效位。 另外,在某些非ModBus通信協(xié)議中也經(jīng)常使用CRC16作為校驗手段,而且產(chǎn)生了一些CRC16的變種,他們是使用CRC16多項式X↑16+X↑15+X↑2+1,單首次裝入的16位寄存器為0000;使用CRC16的反序X↑16+X↑14+X↑1+1,首次裝入寄存器值為0000或FFFFH。 Modbus-RTU通信函數(shù)如下: //modbus-rtu通信得到輸出電頻率
float modbus_rtu(void)
{
float a;
cnttxd=rtu_read_hldreg(LOCALADDR,tx_buf,73,2); //得到發(fā)送數(shù)組的字節(jié)數(shù)
transmit(tx_buf,cnttxd); //發(fā)送,cnttxd為發(fā)送數(shù)組的長度
while(!flag&&RC4==0); //判斷接收數(shù)組長度是否達(dá)到了要求的長度
if(rtu_data_anlys(rx_buf,9)==1) //數(shù)據(jù)分析,檢驗接收到的數(shù)據(jù)對不對
a=receive(rx_buf); //實時接收到儀表的頻率fre
else
a=0;
return a;
} 接口設(shè)計:本模塊的接口電路已在PIC18F4520單片機(jī)最小系統(tǒng)里面集成,值得注意的是本模塊雖然使用的是RS232串行通信模塊,但是由于儀表的通信接口為RS485,儀表與單片機(jī)之間用公—公串口線與RS485轉(zhuǎn)RS232的轉(zhuǎn)接器相連進(jìn)行通信,故實際中即使RS232串行通訊模塊是全雙工的,其中的RC6、RC7本可以在同一時間使用,但是在本模塊下,必須設(shè)置為半雙工工作方式。RS232串行通信電路如下:
圖片1.png (24.55 KB, 下載次數(shù): 132)
下載附件
2018-4-22 16:25 上傳
通信的接線如下:
圖片2.png (207.49 KB, 下載次數(shù): 154)
下載附件
2018-4-22 16:28 上傳
圖片3.png (719.18 KB, 下載次數(shù): 151)
下載附件
2018-4-22 16:28 上傳
最后發(fā)電機(jī)的儀表與單片機(jī)實現(xiàn)的通信結(jié)果如下:
圖片5.png (662.65 KB, 下載次數(shù): 139)
下載附件
2018-4-22 16:31 上傳
|