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