|
RS485通信的特點(diǎn)
n1、采用差分信號(hào)。
n2、RS485通信速率快,最大傳輸速率可以達(dá)到10Mb/s以上。
n3、RS485內(nèi)部采用平衡驅(qū)動(dòng)器和差分接收器的組合,抗干擾能力大大增加。
n4、傳輸距離最遠(yuǎn)可以達(dá)到1200米左右。
n5、可以在總線上進(jìn)行聯(lián)網(wǎng)多機(jī)通信。
n6、RS485接口非常簡(jiǎn)單。
Modbus通信協(xié)議介紹
n1、Modbus產(chǎn)生的背景。
n2、Modbus協(xié)議特點(diǎn)。
n3、RTU協(xié)議幀數(shù)據(jù)
n4、Modbus功能碼
/* 備 注:
* 1、在lesson15_3的基礎(chǔ)上去掉按鍵校時(shí),添加lesson18_2中的Modbus協(xié)議支持
* 2、利用Modbus調(diào)試精靈的寫寄存器功能,可修改日期時(shí)間的每一個(gè)字節(jié)
* 3、寄存器地址0x0000~0x0006分別對(duì)應(yīng)“年/月/日/時(shí)/分/秒/星期”
* 4、RS485方向控制信號(hào)由原來(lái)的P1.7改為P2.0,因本例使用了DS1302而未使用按鍵
*******************************************************************************
*/
#include <reg52.h>
struct sTime { //日期時(shí)間結(jié)構(gòu)體定義
unsigned int year;
unsigned char mon;
unsigned char day;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned char week;
};
bit flag200ms = 1; //200ms定時(shí)標(biāo)志
bit reqRefresh = 0; //時(shí)間刷新請(qǐng)求
struct sTime bufTime; //日期時(shí)間緩沖區(qū)
unsigned char T0RH = 0; //T0重載值的高字節(jié)
unsigned char T0RL = 0; //T0重載值的低字節(jié)
void ConfigTimer0(unsigned int ms);
void RefreshTimeShow();
extern void InitDS1302();
extern void GetRealTime(struct sTime *time);
extern void SetRealTime(struct sTime *time);
extern void UartDriver();
extern void ConfigUART(unsigned int baud);
extern void UartRxMonitor(unsigned char ms);
extern void UartWrite(unsigned char *buf, unsigned char len);
extern unsigned int GetCRC16(unsigned char *ptr, unsigned char len);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
void main()
{
unsigned char psec=0xAA; //秒備份,初值A(chǔ)A確保首次讀取時(shí)間后會(huì)刷新顯示
EA = 1; //開總中斷
ConfigTimer0(1); //配置T0定時(shí)1ms
ConfigUART(9600); //配置波特率為9600
InitDS1302(); //初始化實(shí)時(shí)時(shí)鐘
InitLcd1602(); //初始化液晶
//初始化屏幕上固定不變的內(nèi)容
LcdShowStr(3, 0, "20 - - ");
LcdShowStr(4, 1, " : : ");
while (1)
{
UartDriver(); //調(diào)用串口驅(qū)動(dòng)
if (flag200ms)
{
flag200ms = 0;
GetRealTime(&bufTime); //獲取當(dāng)前時(shí)間
if (reqRefresh || (psec!=bufTime.sec))
{ //檢測(cè)到時(shí)間刷新請(qǐng)求或時(shí)間有變化時(shí)刷新顯示
RefreshTimeShow();
psec = bufTime.sec; //用當(dāng)前值更新上次秒數(shù)
}
}
}
}
/* 將一個(gè)BCD碼字節(jié)顯示到屏幕上,(x,y)-屏幕起始坐標(biāo),bcd-待顯示BCD碼 */
void ShowBcdByte(unsigned char x, unsigned char y, unsigned char bcd)
{
unsigned char str[4];
str[0] = (bcd >> 4) + '0';
str[1] = (bcd&0x0F) + '0';
str[2] = '\0';
LcdShowStr(x, y, str);
}
/* 刷新日期時(shí)間的顯示 */
void RefreshTimeShow()
{
ShowBcdByte(5, 0, bufTime.year);
ShowBcdByte(8, 0, bufTime.mon);
ShowBcdByte(11, 0, bufTime.day);
ShowBcdByte(4, 1, bufTime.hour);
ShowBcdByte(7, 1, bufTime.min);
ShowBcdByte(10, 1, bufTime.sec);
}
/* 串口動(dòng)作函數(shù),根據(jù)接收到的命令幀執(zhí)行響應(yīng)的動(dòng)作
buf-接收到的命令幀指針,len-命令幀長(zhǎng)度 */
void UartAction(unsigned char *buf, unsigned char len)
{
unsigned int crc;
unsigned char crch, crcl;
if (buf[0] != 0x01) //本例中的本機(jī)地址設(shè)定為0x01,
{ //如數(shù)據(jù)幀中的地址字節(jié)與本機(jī)地址不符,
return; //則直接退出,即丟棄本幀數(shù)據(jù)不做任何處理
}
//地址相符時(shí),再對(duì)本幀數(shù)據(jù)進(jìn)行校驗(yàn)
crc = GetCRC16(buf, len-2); //計(jì)算CRC校驗(yàn)值
crch = crc >> 8;
crcl = crc & 0xFF;
if ((buf[len-2]!=crch) || (buf[len-1]!=crcl))
{
return; //如CRC校驗(yàn)不符時(shí)直接退出
}
//地址和校驗(yàn)字均相符后,解析功能碼,執(zhí)行相關(guān)操作
switch (buf[1])
{
case 0x06: //寫入單個(gè)寄存器
if ((buf[2]==0x00) && (buf[3]<=0x06)) //地址0x0000~0x0006分別對(duì)應(yīng)
{ // “年/月/日/時(shí)/分/秒/星期”
GetRealTime(&bufTime); //獲取當(dāng)前時(shí)間
switch (buf[3]) //由寄存器地址決定要修改的時(shí)間位
{
case 0: bufTime.year = 0x2000 + buf[5]; break;
case 1: bufTime.mon = buf[5]; break;
case 2: bufTime.day = buf[5]; break;
case 3: bufTime.hour = buf[5]; break;
case 4: bufTime.min = buf[5]; break;
case 5: bufTime.sec = buf[5]; break;
case 6: bufTime.week = buf[5]; break;
default: break;
}
SetRealTime(&bufTime); //寫入新修改后的時(shí)間
reqRefresh = 1; //設(shè)置顯示刷新請(qǐng)求
len -= 2; //長(zhǎng)度-2以重新計(jì)算CRC并返回原幀
break;
}
else //寄存器地址不被支持時(shí),返回錯(cuò)誤碼
{
buf[1] = 0x86; //功能碼最高位置1
buf[2] = 0x02; //設(shè)置異常碼為02-無(wú)效地址
len = 3;
break;
}
default: //其它不支持的功能碼
buf[1] |= 0x80; //功能碼最高位置1
buf[2] = 0x01; //設(shè)置異常碼為01-無(wú)效功能
len = 3;
break;
}
crc = GetCRC16(buf, len); //計(jì)算返回幀的CRC校驗(yàn)值
buf[len++] = crc >> 8; //CRC高字節(jié)
buf[len++] = crc & 0xFF; //CRC低字節(jié)
UartWrite(buf, len); //發(fā)送返回幀
}
/* 配置并啟動(dòng)T0,ms-T0定時(shí)時(shí)間 */
void ConfigTimer0(unsigned int ms)
{
unsigned long tmp; //臨時(shí)變量
tmp = 11059200 / 12; //定時(shí)器計(jì)數(shù)頻率
tmp = (tmp * ms) / 1000; //計(jì)算所需的計(jì)數(shù)值
tmp = 65536 - tmp; //計(jì)算定時(shí)器重載值
tmp = tmp + 33; //補(bǔ)償中斷響應(yīng)延時(shí)造成的誤差
T0RH = (unsigned char)(tmp>>8); //定時(shí)器重載值拆分為高低字節(jié)
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0為模式1
TH0 = T0RH; //加載T0重載值
TL0 = T0RL;
ET0 = 1; //使能T0中斷
TR0 = 1; //啟動(dòng)T0
}
/* T0中斷服務(wù)函數(shù),執(zhí)行按鍵掃描和200ms定時(shí) */
void InterruptTimer0() interrupt 1
{
static unsigned char tmr200ms = 0;
TH0 = T0RH; //重新加載重載值
TL0 = T0RL;
UartRxMonitor(1); //串口接收監(jiān)控
tmr200ms++;
if (tmr200ms >= 200) //定時(shí)200ms
{
tmr200ms = 0;
flag200ms = 1;
}
}
|
-
-
Modbus注意要項(xiàng).pdf
2021-7-5 22:47 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
216.87 KB, 下載次數(shù): 96, 下載積分: 黑幣 -5
-
-
MODBUS協(xié)議中文版.pdf
2021-7-5 22:47 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
1.11 MB, 下載次數(shù): 114, 下載積分: 黑幣 -5
-
-
Modbus通信協(xié)議.pdf
2021-7-5 22:47 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
156.79 KB, 下載次數(shù): 88, 下載積分: 黑幣 -5
-
-
MAX485.pdf
2021-7-5 22:47 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
438.77 KB, 下載次數(shù): 85, 下載積分: 黑幣 -5
-
-
例程.7z
2021-7-5 22:55 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
18.93 KB, 下載次數(shù): 138, 下載積分: 黑幣 -5
評(píng)分
-
查看全部評(píng)分
|