移植的《手把手教你51單片機》的Modbus 程序到普中的STC89C51單片機,移植的是案例二。用Modbus調試一直顯示讀入超時。然后老師幫忙修改后可以在LCD上顯示字符,但是Modbus調試精靈上一直顯示讀寫超時。不能返回值,也不能讀寫。請問除了要修改lcd1602的引腳外,還需要哪些修改???、單片機是普中的A6,請問怎么修改程序。
============================================================================
這是RS485.C的代碼,老師修改了
============================================================================
#include <reg52.h>
#include <intrins.h>
sbit BUZZ = P1^6;
sbit RS485_DIR = P1^7; //RS485方向選擇引腳
bit flagOnceTxd = 0; //單次發送完成標志,即發送完一個字節
bit cmdArrived = 0; //命令到達標志,即接收到上位機下發的命令
unsigned char cntRxd = 0;
unsigned char idata bufRxd[20]; //串口接收緩沖區 idata
unsigned char regGroup[5]; //Modbus寄存器組,地址為0x00~0x04
extern void LcdWriteDat(unsigned char dat); //寫入數據函數 /////
extern bit flagBuzzOn;
extern void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str);
extern unsigned int GetCRC16(unsigned char *ptr, unsigned char len);
void ConfigUART(unsigned int baud) //串口配置函數,baud為波特率
{
RS485_DIR = 0; //RS485設置為接收方向
SCON = 0x50; //配置串口為模式1
TMOD &= 0x0F; //清零T1的控制位
TMOD |= 0x20; //配置T1為模式2
TH1 = 256 - (11059200/12/32) / baud; //計算T1重載值
TL1 = TH1; //初值等于重載值
ET1 = 0; //禁止T1中斷
ES = 1; //使能串口中斷
TR1 = 1; //啟動T1
}
unsigned char UartRead(unsigned char *buf, unsigned char len) //串口數據讀取函數,數據接收指針buf,讀取數據長度len,返回值為實際讀取到的數據長度
{
unsigned char i;
if (len > cntRxd) //讀取長度大于接收到的數據長度時,
{
len = cntRxd; //讀取長度設置為實際接收到的數據長度
}
for (i=0; i<len; i++) //拷貝接收到的數據
{
*buf = bufRxd[i];
buf++;
}
cntRxd = 0; //清零接收計數器
return len; //返回實際讀取長度
}
void DelayX10us(unsigned char t) //軟件延時函數,延時時間(t*10)us
{
do {
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while (--t);
}
void UartWrite(unsigned char *buf, unsigned char len) //串口數據寫入函數,即串口發送函數,待發送數據指針buf,數據長度len
{
RS485_DIR = 1; //RS485設置為發送
while (len--) //發送數據
{
flagOnceTxd = 0;
SBUF = *buf;
buf++;
while (!flagOnceTxd);
}
DelayX10us(5); //等待最后的停止位完成,延時時間由波特率決定
RS485_DIR = 0; //RS485設置為接收
}
void UartDriver() //串口驅動函數,檢測接收到的命令并執行相應動作
{
unsigned char i;
unsigned char cnt;
unsigned char len;
unsigned char buf[30];
unsigned char str[4];
unsigned int crc;
unsigned char crch, crcl;
unsigned char tmp;///
unsigned char a;
if (cmdArrived) //有命令到達時,讀取處理該命令
{
cmdArrived = 0;
// LcdWriteDat(0x31);////
len = UartRead(buf, sizeof(buf)); //將接收到的命令讀取到緩沖區中
LcdWriteDat(len+0x30);////
if (buf[0] == 0x01) //核對地址以決定是否響應命令,本例中的本機地址為0x01
{
crc = GetCRC16(buf, len-2); //計算CRC校驗值
crch = crc >> 8;
crcl = crc & 0xFF;
// if ((buf[len-2]!=crch) || (buf[len-1]!=crcl))
// {
// return; //如CRC校驗不符時直接退出
// }
////// 1
// tmp = crch; //crcl顯示到液晶上
tmp = buf[6]; //
tmp =tmp >> 4;
if (tmp >= 0xA)
str[0] = tmp - 0xA + 'A';
else
str[0] = tmp + '0';
LcdWriteDat(str[0]);
// tmp = crch & 0x0F;
tmp = buf[6] & 0x0F;
if (tmp >= 0xA)
str[1] = tmp - 0xA + 'A';
else
str[1] = tmp + '0';
LcdWriteDat(str[1]);
///// 1
if ((buf[len-2] == crch) && (buf[len-1] == crcl)) //判斷CRC校驗是否正確
{
switch (buf[1]) //按功能碼執行操作
{
case 0x03: //讀取一個或連續的寄存器
if ((buf[2] == 0x00) && (buf[3] <= 0x05)) //寄存器地址支持0x0000~0x0005
{
if (buf[3] <= 0x04)
{
i = buf[3]; //提取寄存器地址
cnt = buf[5]; //提取待讀取的寄存器數量
buf[2] = cnt*2; //讀取數據的字節數,為寄存器數*2,因Modbus定義的寄存器為16位
len = 3;
while (cnt--)
{
buf[len++] = 0x00; //寄存器高字節補0
buf[len++] = regGroup[i++]; //寄存器低字節
}
}
else //地址0x05為蜂鳴器狀態
{
buf[2] = 2; //讀取數據的字節數
buf[3] = 0x00;
buf[4] = flagBuzzOn;
len = 5;
}
break;
}
else //寄存器地址不被支持時,返回錯誤碼
{
buf[1] = 0x83; //功能碼最高位置1
buf[2] = 0x02; //設置異常碼為02-無效地址
len = 3;
break;
}
case 0x06: //寫入單個寄存器
if ((buf[2] == 0x00) && (buf[3] <= 0x05)) //寄存器地址支持0x0000~0x0005
{
if (buf[3] <= 0x04)
{
i = buf[3]; //提取寄存器地址
regGroup[i] = buf[5]; //保存寄存器數據
cnt = regGroup[i] >> 4; //顯示到液晶上
if (cnt >= 0xA)
str[0] = cnt - 0xA + 'A';
else
str[0] = cnt + '0';
cnt = regGroup[i] & 0x0F;
if (cnt >= 0xA)
str[1] = cnt - 0xA + 'A';
else
str[1] = cnt + '0';
str[2] = '\0';
LcdShowStr(i*3, 1, str);
}
else //地址0x05為蜂鳴器狀態
{
flagBuzzOn = (bit)buf[5]; //寄存器值轉換為蜂鳴器的開關
}
len -= 2; //長度-2以重新計算CRC并返回原幀
break;
}
else //寄存器地址不被支持時,返回錯誤碼
{
buf[1] = 0x86; //功能碼最高位置1
buf[2] = 0x02; //設置異常碼為02-無效地址
len = 3;
break;
}
default: //其它不支持的功能碼
buf[1] |= 0x80; //功能碼最高位置1
buf[2] = 0x01; //設置異常碼為01-無效功能
len = 3;
break;
}
crc = GetCRC16(buf, len); //計算CRC校驗值
buf[len++] = crc >> 8; //CRC高字節
buf[len++] = crc & 0xFF; //CRC低字節
UartWrite(buf, len); //發送響應幀
}
}
}
}/// UartDriver
void UartDriver1() //串口驅動函數,檢測接收到的命令并執行相應動作
{
unsigned char i;
unsigned char cnt;
unsigned char len;
unsigned char buf[30];
unsigned char str[4];
unsigned int crc;
unsigned char crch, crcl;
unsigned char tmp;
if (cmdArrived) //有命令到達時,讀取處理該命令
{
cmdArrived = 0;
LcdWriteDat(0x37);
len = UartRead(buf, sizeof(buf)); //將接收到的命令讀取到緩沖區中
i = buf[3]; //提取寄存器地址
regGroup[i] = buf[5]; //保存寄存器數據
cnt = regGroup[i] >> 4; //顯示到液晶上
if (cnt >= 0xA)
str[0] = cnt - 0xA + 'A';
else
str[0] = cnt + '0';
cnt = regGroup[i] & 0x0F;
if (cnt >= 0xA)
str[1] = cnt - 0xA + 'A';
else
str[1] = cnt + '0';
str[2] = '\0';
LcdShowStr(i*3, 0, str);
}
}/// UartDriver
void UartRxMonitor(unsigned char ms) //串口接收監控函數
{
static unsigned char cntbkp = 0;
static unsigned char idletmr = 0;
if (cntRxd > 0) //接收計數器大于零時,監控總線空閑時間
{
if (cntbkp != cntRxd) //接收計數器改變,即剛接收到數據時,清零空閑計時
{
cntbkp = cntRxd;
idletmr = 0;
}
else
{
if (idletmr < 5) //接收計數器未改變,即總線空閑時,累積空閑時間
{
idletmr += ms;
if (idletmr >= 5) //空閑時間超過4個字節傳輸時間即認為一幀命令接收完畢
{
cmdArrived = 1; //設置命令到達標志
}
}
}
}
else
{
cntbkp = 0;
}
}
void InterruptUART() interrupt 4 //UART中斷服務函數
{
if (RI) //接收到字節
{
RI = 0; //手動清零接收中斷標志位
if (cntRxd < sizeof(bufRxd)) //接收緩沖區尚未用完時,
{
bufRxd[cntRxd++] = SBUF; //保存接收字節,并遞增計數器
}
}
if (TI) //字節發送完畢
{
TI = 0; //手動清零發送中斷標志位
flagOnceTxd = 1; //設置單次發送完成標志
}
}
================================================================
這是main.c 的源程序
================================================================
#include <reg52.h>
sbit BUZZ = P1^6; //蜂鳴器控制引腳
bit flagBuzzOn = 0; //蜂鳴器啟動標志
unsigned char T0RH = 0; //T0重載值的高字節
unsigned char T0RL = 0; //T0重載值的低字節
void ConfigTimer0(unsigned int ms);
extern void LcdInit();
extern void ConfigUART(unsigned int baud);
extern void UartRxMonitor(unsigned char ms);
extern void UartDriver();
void main ()
{
EA = 1; //開總中斷
ConfigTimer0(1); //配置T0定時1ms
ConfigUART(4800); //配置波特率為9600///4800
LcdInit(); //初始化液晶
while(1)
{
UartDriver();
}
}
void ConfigTimer0(unsigned int ms) //T0配置函數
{
unsigned long tmp;
tmp = 11059200 / 12; //定時器計數頻率
tmp = (tmp * ms) / 1000; //計算所需的計數值
tmp = 65536 - tmp; //計算定時器重載值
tmp = tmp + 34; //修正中斷響應延時造成的誤差
T0RH = (unsigned char)(tmp >> 8); //定時器重載值拆分為高低字節
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0為模式1
TH0 = T0RH; //加載T0重載值
TL0 = T0RL;
ET0 = 1; //使能T0中斷
TR0 = 1; //啟動T0
}
void InterruptTimer0() interrupt 1 //T0中斷服務函數
{
TH0 = T0RH; //定時器重新加載重載值
TL0 = T0RL;
if (flagBuzzOn) //蜂鳴器鳴叫或關閉
BUZZ = ~BUZZ;
else
BUZZ = 1;
UartRxMonitor(1); //串口接收監控
}
====================================================================
這是LCD1602.c
===================================================================
////5-14
#include <reg52.h>
#define LCD1602_DB P0
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_E = P2^7;
void LcdWaitReady() //等待液晶準備好
{
unsigned char sta;
LCD1602_DB = 0xFF;
LCD1602_RS = 0;
LCD1602_RW = 1;
do
{
LCD1602_E = 1;
sta = LCD1602_DB; //讀取狀態字
LCD1602_E = 0;
} while (sta & 0x80); //bit7等于1表示液晶正忙,重復檢測直到其等于0為止
}
void LcdWriteCmd(unsigned char cmd) //寫入命令函數
{
LcdWaitReady();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_E = 1;
LCD1602_E = 0;
}
void LcdWriteDat(unsigned char dat) //寫入數據函數
{
LcdWaitReady();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_E = 1;
LCD1602_E = 0;
}
void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str) //顯示字符串,屏幕起始坐標(x,y),字符串指針str
{
unsigned char addr;
//由輸入的顯示坐標計算顯示RAM的地址
if (y == 0)
addr = 0x00 + x; //第一行字符地址從0x00起始
else
addr = 0x40 + x; //第二行字符地址從0x40起始
//由起始顯示RAM地址連續寫入字符串
LcdWriteCmd(addr | 0x80); //寫入起始地址
while (*str != '\0') //連續寫入字符串數據,直到檢測到結束符
{
LcdWriteDat(*str);
str++;
}
}
void LcdInit() //液晶初始化函數
{
LcdWriteCmd(0x38); //16*2顯示,5*7點陣,8位數據接口
LcdWriteCmd(0x0C); //顯示器開,光標關閉
LcdWriteCmd(0x06); //文字不動,地址自動+1
LcdWriteCmd(0x01); //清屏
}
==============================================================
這是CRC16.c
==============================================================
unsigned int GetCRC16(unsigned char *ptr, unsigned char len)
{
unsigned int index;
unsigned char crch = 0xFF; //高CRC字節
unsigned char crcl = 0xFF; //低CRC字節
unsigned char code TabH[] = { //CRC高位字節值表
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
unsigned char code TabL[] = { //CRC低位字節值表
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
} ;
while (len--) //計算指定長度的CRC
{
index = crch ^ *ptr++;
crch = crcl ^ TabH[index];
crcl = TabL[index];
}
return ((crch<<8) | crcl);
}
|