标题:
最近做的一个东西, 涉及到单片机定时器使用, UART, RS485, STC单片机片内EEPROM操作.
[打印本页]
作者:
ping264888
时间:
2019-5-15 09:01
标题:
最近做的一个东西, 涉及到单片机定时器使用, UART, RS485, STC单片机片内EEPROM操作.
如题, 提供给大家参考. 也欢迎大神指正.
工程文档在附件中.
单片机源程序如下:
#include "reg51.h"
#include "main.h"
#include "EEPROM.h"
#define uchr unsigned char
#define uint unsigned int
//#define FOSC 11059200L //System frequency
#define FOSC 12000000L //System frequency
//#define BAUD 9600 //UART baudrate
#define T1MS (65536-FOSC/12/1000) //1ms timer calculation method in 12T mode
#define ON 1 //定義ON
#define OFF 0 //定義OFF
#define STARTBYTE 0x24 //開始字節
#define STOPBYTE 0x2a //結束字節
#define UART_P1() (AUXR1 |= 0x80) //串口切換到P1口
#define UART_P3() (AUXR1 &= 0x7f) //串口切換到P3口
uchr Settings[2]; //從EEPROM讀取的設定
uchr addr; //系統地址
bit PowerONWhenSTARTUP; //系統上電ESD是否開啟(保留)
bit flagRec_OK; //標誌位, 接收完成
bit flagBusy; //標誌位, 發送忙
uchr recBuff[5]; //接收緩存
bit flagWriteEN; //標誌位, 寫地址使能
uchr ESDState; //ESD狀態 1-> PASS, 2 -> FAIL, 3 -> POWEROFF, 4 -> IDLE
uchr PowerState; //ESD電源狀狀態 0-> 關閉, 1-> 開啟, 2->空閒.
sfr AUXR = 0x8e; //輔助寄存器
sfr AUXR1 = 0xa2; //串口選擇寄存器
sfr BRT = 0x9c;
sbit pin485EN = P1^4; //485寫使能
sbit pinESDState= P1^3; //ESD偵測
sbit pinLampG = P1^2; //綠燈
sbit pinLampR = P1^1; //紅燈
sbit pinESDPower= P1^0; //ESD電源
sbit pinWriteEN = P3^5; //寫地址使能
sbit pinSensor = P3^7; //感應器
extern void delayms(uint ms); //毫秒延時函數
extern void SysInit(void); //系統初始化
extern void sendData(uchr dat); //發送1Byte
extern void UartSend(uchr cmd,dat); //發送一幀
extern void UartDriver(void); //串口數據處理
extern void LampControl(uchr t); //燈控制
extern void UartChangePort(void); //串口切換
extern void HumanDetection(void); //人員檢測
/**************主函數******************/
void main(void)
{
SysInit();
for(;;)
{
UartChangePort();
HumanDetection();
UartDriver();
if(PowerState == 1) LampControl(ESDState);
}
}
//#############################
//毫秒延時
//#############################
void delayms(uint ms)
{
unsigned char i, j;
do{
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
} while (--ms);
}
//#############################
//發送1byte
//#############################
void sendData(uchr dat)
{
while(flagBusy); //檢測是否還在發送狀態
flagBusy = 1;
SBUF = dat;
}
//#############################
//發送1幀
//485接收發送狀態轉換時應提前, 以適應電路的反應時間. 特別是發送完成. 延時不夠易造成停止位發送失敗.
//#############################
void UartSend(uchr cmd,dat)
{
pin485EN = 0; //485發送使能
delayms(1); //延時
sendData(STARTBYTE); //發送開始位
sendData(addr); //發送地址
sendData(cmd); //發送指令
sendData(dat); //發送數據
sendData(STOPBYTE); //發送結束位
delayms(1); //延時,此時發送停止位
pin485EN = 1; //485發送禁止
}
//#############################
//人員檢測, 僅在電源開啟時起作用
//#############################
void HumanDetection(void)
{
static uint DetecCount = 0;
if(DetecCount <= 3000) //設置檢測間隔時間, 防止人員動作造成誤判
{
delayms(1);
DetecCount++;
} else {
DetecCount = 0;
if(PowerState == 1) //確認為開啟狀態
{
if(pinSensor == 1) //確認人員離開
{
delayms(200);
if(pinSensor == 1)
{
PowerState = 2; //進入空閒狀態
pinLampG = OFF; //綠燈
pinLampR = OFF; //紅燈
pinESDPower = OFF; //ESD電源
}
}
} else if(PowerState == 2) //空閒狀態
{
if(pinSensor == 0) //確認人員就位
{
delayms(200);
if(pinSensor == 0)
{
PowerState = 1; //進入開啟狀態
pinESDPower = ON; //ESD電源
}
}
}
}
}
//#############################
//燈控制
// 1-> 綠燈 2-> 紅燈 其他燈滅
//#############################
void LampControl(uchr t)
{
static uchr lampState = 4; //上一次的燈狀態, 燈狀態只有0,1,2. 默認4防止上電后狀態不變燈顯示錯誤.
if(lampState != t)
{
lampState = t;
pinLampG = OFF;
pinLampR = OFF;
switch(t)
{
case 1:
pinLampG = ON;
break;
case 2:
pinLampR = ON;
break;
default:
break;
}
}
}
//#############################
//串口切換
//單片機默認串口在P3, 所以初始化的時候不用設置
//#############################
void UartChangePort(void)
{
static uchr UartPort;
if(UartPort != pinWriteEN) //用個標誌位判斷防止不斷寫寄存器
{
UartPort = pinWriteEN;
if(pinWriteEN == 0) //下載端口最後一pin短接到地時, 串口從P1切換到P3. 可使用TTL進行通信調試.
{
UART_P3();
} else {
UART_P1();
}
}
}
//#############################
//串口數據處理
//檢查接收完成狀態位flagRec_OK為1, 進函數進行處理.
//#############################
void UartDriver(void)
{
uchr returnDat; //返回的數據
uchr returnCmd; //返回的指令
uchr recCmd; //收到的指令
uchr recDat; //收到的數據
if(flagRec_OK) //判斷接收標誌位
{
flagRec_OK = 0;
if((recBuff[1] == addr) || recBuff[1] == 0xff) //判斷數據幀中的地址位是否與本機一致, 或者數據幀的地址位廣播地址0xff
{
recCmd = recBuff[2];
returnCmd = recCmd;
recDat = recBuff[3];
returnDat = 1;
switch(recCmd)
{
case 0x11: //感應器測試
returnDat = pinSensor;
break;
case 0x22: //ESD狀態
returnDat = ESDState;
break;
case 0x30: //關閉ESD電源
PowerState = 0;
pinESDPower = OFF;
pinLampG = OFF;
pinLampR = OFF;
break;
case 0x31: //開啟ESD電源
PowerState = 1;
pinESDPower = ON;
break;
case 0x41: //開綠燈, 只能在ESD關閉狀態下
if(PowerState == 0)
{
pinLampG = ON;
pinLampR = OFF;
} else {
returnDat = 0;
}
break;
case 0x42: //開紅燈, 只能在ESD關閉狀態下
if(PowerState == 0)
{
pinLampG = OFF;
pinLampR = ON;
} else {
returnDat = 0;
}
break;
case 0x50: //使能地址寫
flagWriteEN = 1;
break;
case 0x51: //寫地址
//if((flagWriteEN == 1) && (pinWriteEN == 0)) //檢查地址寫是否使能
if(flagWriteEN == 1) //檢查地址寫是否使能
{
Settings[0] = recDat;
addr = recDat;
ISP_IAP_EraseData(0);
ISP_IAP_WriteData(0,Settings,2);
} else {
returnDat = 0;
}
break;
default: //無法匹配的指令返回0xff
returnDat = 0xff;
break;
}
UartSend(returnCmd, returnDat); //發送返回數據
}
}
}
//#############################
//系統初始化
//#############################
void SysInit(void)
{
///*******寄存器初始化**********/
TL0 = T1MS; //計時器0 1毫秒 初值
TH0 = T1MS >> 8;
TR0 = 1; //開啟計時器0
ET0 = 1; //開啟計時器0中斷
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位數據,可變波特率
BRT = 0xD9; //獨立波特率初裝值
AUXR |= 0x04; //獨立波特率1T
AUXR |= 0x01; //串口1波特率發生器選擇為獨立波特率發生器
AUXR |= 0x10; //啟動獨立波特率發生器
UART_P1(); //將串口切換到P1口
ES = 1; //開串口中斷
EA = 1; //開總中斷
/*******設定初始化**************/
ISP_IAP_ReadData(0x00,Settings,2); //從EEPROM中讀取3個Byte資料
addr = Settings[0]; //地址
PowerONWhenSTARTUP = (bit)(Settings[1]); //開機狀態, 先做在這裡, 但不做處理
/*******端口初始化*************/
pin485EN = 1; //禁止485發送, 備註: 485默認通過電阻弱下拉, 接收狀態, 使能端低電平使光耦導通, 485使能端轉為高電平發送狀態.
pinESDState = 1;
pinWriteEN = 1;
pinESDPower = ON;
pinLampG = OFF;
pinLampR = OFF;
/*******變量初始化**************/
PowerState = 1; //默認電源開啟
flagWriteEN = 0; //禁止寫地址
}
//#############################
//串口中斷, 接收上位機數據
//數據幀格式
// 24 | 地址 | 指令 | 數據 | 2A
//開始位 | 地址位 | 指令位 | 數據位 | 結束位
//#############################
void uart_isr() interrupt 4
{
static bit recStart; //接收開始
static bit recStop; //接收結束
static uchr recIdx; //接收序號
uchr recTmp; //接收緩存
if(TI) //發送
{
TI = 0;
flagBusy = 0;
} else { //接收
RI = 0;
recTmp = SBUF;
if((recTmp == STARTBYTE) && (recStart == 0)) //判斷接收開始
{
recStart = 1;
recStop = 0;
recIdx = 0;
flagRec_OK = 0;
}
if((recStart == 1) && (recStop == 0)) //接收數據
{
recBuff[recIdx++] = recTmp;
if((recTmp == STOPBYTE) || (recIdx >= 5)) //判斷接收結束
{
recStop = 1;
recStart = 0;
flagRec_OK = 1;
}
}
}
}
//#############################
//計時器0中斷函數, 用於獲取ESD狀態
//數據來源是一個指示異常的閃爍紅燈LED電壓, 燈亮時為0, 燈滅為1.
//#############################
void tm0_isr() interrupt 1 using 1
{
static uint count;
static uchr lampStates[8]; //採集的狀態, 共8個
static uchr lampStateIdx; //燈狀態數據Idx
uchr i;
TL0 = T1MS; //reload timer0 low byte
TH0 = T1MS >> 8; //reload timer0 high byte
if (count++ == 250) //每250毫秒採集一次紅燈的狀態, 保存在狀態數組中, 從數組判斷當前系統的狀態
{
count = 0; //reset counter
if(PowerState == 0) //關閉狀態, 採集狀態 = 3
{
lampStates[lampStateIdx++] = 3;
} else if(PowerState == 1) //開啟狀態, 採集狀態 = 紅燈關聯
{
lampStates[lampStateIdx++] = pinESDState ? 1 : 2;
} else if(PowerState == 2){ //空閒狀態, 採集狀態 = 4
lampStates[lampStateIdx++] = 4;
}
if(lampStateIdx >=8) //分析採集數組
{
lampStateIdx = 0;
for(i=0; i<8; i++)
{
if(lampStates[i] == 4) //如有採集結果中有4, 狀態為空閒
{
ESDState = 4;
break;
} else if(lampStates[i] == 3) //如有採集結果中有3, 狀態為關閉
{
ESDState = 3;
break;
} else if(lampStates[i] == 2) //如果採集結果中有2, 狀態為異常
{
ESDState = 2;
break;
} else { //否則, 狀態為正常.
ESDState = 1;
}
}
}
}
}
复制代码
全部资料51hei下载地址:
ESDMonitor.zip
(57.42 KB, 下载次数: 24)
2019-5-15 08:59 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
kepuple
时间:
2019-6-4 20:35
谢谢楼主!
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1