|
GYJ-0310_A 某一個寶描述_01.jpg (342.28 KB, 下載次數: 29)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_02.jpg (187.64 KB, 下載次數: 29)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_03.jpg (178.41 KB, 下載次數: 36)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_04.jpg (384.16 KB, 下載次數: 30)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_05.jpg (254.71 KB, 下載次數: 28)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_06.jpg (374.98 KB, 下載次數: 28)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_07.jpg (349.05 KB, 下載次數: 30)
下載附件
2023-7-3 10:33 上傳
GYJ-0310_A 某一個寶描述_08.jpg (632.9 KB, 下載次數: 25)
下載附件
2023-7-3 10:33 上傳
【聲明】此程序僅用于學習與參考!
*********************************************************************/
/********************************************************************
宏定義
*********************************************************************/
#include<STC15W408AS.h> //庫文件
#include<intrins.h>
#define uchar unsigned char//宏定義無符號字符型
#define uint unsigned int //宏定義無符號整型
#define ADC_POWER 0x80 //ADC 電源控制位
#define ADC_FLAG 0x10 //ADC 轉換結束標志位
#define ADC_START 0x08 //ADC 開始轉換控制位
#define ADC_SPEEDLL 0x00 //210 個時鐘周期轉換一次
#define ADC_SPEEDL 0x20 //420 個時鐘周期轉換一次
#define ADC_SPEEDH 0x40 //630 個時鐘周期轉換一次
#define ADC_SPEEDHH 0x60 //840 個時鐘周期轉換一次
typedef unsigned char INT8U;
typedef unsigned int INT16U;
#define ENABLE_ISP 0x82 //系統工作時鐘<20MHz 時,對IAP_CONTR 寄存器設置此值
#define WD1 0x5a //使用STC11xx系列單片機時,先寫入0x5a,然寫入0xa5
#define WD2 0xa5
char IAPAddr=0;
/********************************************************************
初始定義
*********************************************************************/
code uchar seg7code[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //顯示段碼 數碼管字跟
/********************************************************************
I/O定義
*********************************************************************/
bit z=0,ba=0,k=0,zs=0,kk=0,sd=0,sd1=0;
uchar y=0,smg2=0,s1=0,s2=0,ii=0,dat3=0,dat4=0,dat5=0,h_1=0,l_1=0;
uint s=0,bai=0,shi=0,ge=0,js=0,js1=0,js2=0,js3=0,dat=0,dat1=0,dat2=0,h_2=0,l_2=0;
sbit aj1=P3^1;
sbit aj2=P3^0;
sbit out=P3^4;
sbit L1=P3^5;//數碼管位控制
sbit L2=P3^6;//數碼管位控制
sbit L3=P3^7;//數碼管位控制
sbit dp=P3^3;//小數點
sbit btv_1=P5^4;
sbit btv_2=P5^5;
sbit zc=P3^2;
bit kt=0,kt_1=0,bz=0,bz2=0;bz3=0;//超設定值發送標志位,bz2數碼管閃爍標志位
bit bb_1=0,bb_2=0,bb_3=0,bb_4=0;//調整波特率標志位
uchar ss=0,hz=0,lz=0;
uchar trg=0,trg_1=0,cont=0,cont_1=0;
uchar ReadData=0,ReadData_1=0;
bit flagOnceTxd = 0; //單次發送完成標志,即發送完一個字節
bit cmdArrived = 0; //命令到達標志,即接收到上位機下發的命令
unsigned char cntRxd = 0;
unsigned char pdata bufRxd[30]; //串口接收緩沖區
void UartDriver();
unsigned char UartRead(unsigned char *buf, unsigned char len);
void UartWrite(unsigned char *buf, unsigned char len);
void UartRxMonitor(unsigned char ms);
/********************************************************************
16進制轉10進制函數
*********************************************************************/
void HexToDec(uchar redat)
{
h_1 = redat>>4;
l_1 = redat&0x0f;
switch(h_1)
{
case 0:h_1=0;break;
case 1:h_1=1;break;
case 2:h_1=2;break;
case 3:h_1=3;break;
case 4:h_1=4;break;
case 5:h_1=5;break;
case 6:h_1=6;break;
case 7:h_1=7;break;
case 8:h_1=8;break;
case 9:h_1=9;break;
default:break;
}
switch(l_1)
{
case 0:l_1=0;break;
case 1:l_1=1;break;
case 2:l_1=2;break;
case 3:l_1=3;break;
case 4:l_1=4;break;
case 5:l_1=5;break;
case 6:l_1=6;break;
case 7:l_1=7;break;
case 8:l_1=8;break;
case 9:l_1=9;break;
default:break;
}
}
/********************************************************************
10進制轉10進制函數
*********************************************************************/
void HexToHex(uchar redat)
{
h_2 = redat/10;
l_2 = redat%10;
switch(h_2)
{
case 0:h_2=0x00;break;
case 1:h_2=0x10;break;
case 2:h_2=0x20;break;
case 3:h_2=0x30;break;
case 4:h_2=0x40;break;
case 5:h_2=0x50;break;
case 6:h_2=0x60;break;
case 7:h_2=0x70;break;
case 8:h_2=0x80;break;
case 9:h_2=0x90;break;
default:break;
}
switch(l_2)
{
case 0:l_2=0x00;break;
case 1:l_2=0x01;break;
case 2:l_2=0x02;break;
case 3:l_2=0x03;break;
case 4:l_2=0x04;break;
case 5:l_2=0x05;break;
case 6:l_2=0x06;break;
case 7:l_2=0x07;break;
case 8:l_2=0x08;break;
case 9:l_2=0x09;break;
default:break;
}
}
/********************************************************************
E2P函數
*********************************************************************/
union union_temp16
{
INT16U un_temp16;
INT8U un_temp8[2];
}my_unTemp16;
INT8U Byte_Read(INT16U add); //讀一字節,調用前需打開IAP 功能
void Byte_Program(INT16U add, INT8U ch); //字節編程,調用前需打開IAP 功能
void Sector_Erase(INT16U add); //擦除扇區
void IAP_Disable(); //關閉IAP 功能
/********************************************************************
AD轉換初始化程序
*********************************************************************/
void InitADC()
{
P1ASF = 0x80; //設置P1.7口AD轉換,必須加
P1M0=0X80;
P1M1=0X80; //設置P1.7口為開漏模式,使用AD功能
ADC_RES = 0; //AD數據寄存器清空
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;//打開AD電源,轉換周期210
_nop_(); //延時一個機器周期
_nop_();
_nop_(); //延時一個機器周期
}
/********************************************************************
AD轉換控制程序
*********************************************************************/
uchar ADCRead(uchar px) //轉換輸出的數據 (PX為通道口)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDLL |px| ADC_START;//開始轉換
_nop_(); //延時一個機器周期
_nop_(); //延時一個機器周期
_nop_(); //延時一個機器周期
_nop_(); //延時一個機器周期
while (!(ADC_CONTR & ADC_FLAG));//等待轉換結束
ADC_CONTR &= ~ADC_FLAG; //關閉AD轉換
return ADC_RES; //返回數據
}
/*******************************************************************
* 讀取按鍵狀態
********************************************************************/
void KeyRead()//讀取按鍵IO口函數
{
ReadData = aj1^0xff; // 讀取按鍵狀態取反后賦值給ReadData
trg = ReadData & (ReadData ^ cont); //trg短按,每按下按鍵trg=1;抬手后為trg=0,長按為trg=0
cont = ReadData; //cont長按,長按cont=1,抬手后cont=0
ReadData_1 = aj2^0xff; // 讀取按鍵狀態取反后賦值給ReadData
trg_1 = ReadData_1 & (ReadData_1 ^ cont_1); //trg短按,每按下按鍵trg=1;抬手后為trg=0,長按為trg=0
cont_1 = ReadData_1; //cont長按,長按cont=1,抬手后cont=0
}
/*******************************************************************
* 按鍵
********************************************************************/
void key_1()
{
if(trg & 0x01) //短按
{
kt_1=0;
kt=1; //這是短按標志位,kt=1說明短按了
}
if((aj1!=0)&&(kt==1))//判斷
{
z=1; // 選位標志位
y++; //選位
out=1;
if(y==4)
{
z=0;
k=1;
y=0;
// s=s1+s2+s3;
}
kt=0;
} // 短按
}
void key_2()
{
if(trg_1 & 0x01) //短按
{
kt=0;
kt_1=1; //這是短按標志位,kt=1說明短按了
}
if((aj2!=0)&&(kt_1==1))//判斷
{
if(y==1)
{
s1++;
if(s1>9)
{
s1=0;
}
}
if(y==2)
{
s2+=10;
if(s2>20)
{
s2=0;
}
}
s=s1+s2;
kt_1=0;
} // 短按
}
/*******************************************************************
* 串口驅動
********************************************************************/
void UartDriver() //串口驅動函數,檢測接收到的命令并執行相應動作
{
unsigned char len;
xdata unsigned char buf[30];
if (cmdArrived) //有命令到達時,讀取處理該命令
{
cmdArrived = 0;
len = UartRead(buf, sizeof(buf)); //將接收到的命令讀取到緩沖區中
if ((buf[0] == 0xAA)&&(buf[1] == ss)&&(buf[2] == 0x01)&&(buf[4] == 0xBB)&&(len == 5)) //修改板子地址
{
ss=buf[3];k=1;
buf[0] = 0xAA;
buf[1] = ss;
buf[2] = 0x01;
buf[3] = 0x01;
buf[4] = 0xBB;
len = 5;
UartWrite(buf, len);
}
if((buf[0] == 0xAA)&&(buf[1] == ss)&&(buf[2] == 0x06)&&(buf[3] == 0x01)&&(buf[4] == 0xBB)&&(len == 5)) //查詢溫度
{
HexToDec(dat1);
dat3 = h_1*16+l_1; //轉換為10進制
h_1=0;l_1=0;
HexToHex(dat3); //10進制轉換為16進制
dat4 = h_2|l_2;
h_2=0;l_2=0;
buf[0] = 0xAA;
buf[1] = ss;
buf[2] = 0x06;
buf[3] = dat4;
buf[4] = 0xBB;
len = 5;
UartWrite(buf,len);
}
if ((buf[0] == 0xAA)&&(buf[1] == 0x00)&&(buf[2] == 0x00)&&(buf[3] == 0x00)&&(buf[4] == 0xBB)&&(len == 5)) //查詢板子地址
{
buf[0] = 0xAA;
buf[1] = ss;
buf[2] = 0x00;
buf[3] = 0x00;
buf[4] = 0xBB;
len = 5;
UartWrite(buf, len);
}
}
}
/*******************************************************************
* 定時器配置
********************************************************************/
void ConfigTimer0(){
TMOD=0x01;//將定時器0,1都設置為模式1
TH0=0XFC;//1ms
TL0=0X66;
TR0=1;//開啟定時器0
ET0=1;//開定時器0的中斷
EA=1;//開總中斷
}
/*******************************************************************
* 串口配置
********************************************************************/
void ConfigUART() //串口配置函數,baud為波特率
{
SCON = 0x50; //8位數據,可變波特率
AUXR |= 0x01; //串口1選擇定時器2為波特率發生器
AUXR |= 0x04; //定時器2時鐘為Fosc,即1T
T2L = lz; //設定定時初值
T2H = hz; //設定定時初值
AUXR |= 0x10; //啟動定時器2
ES = 1; //使能串口中斷
}
/*******************************************************************
* 顯示
********************************************************************/
void led(uint date)
{
bai=date/100;
shi=date%100/10;
ge=date%10;
}
/*******************************************************************
* t0定時器
********************************************************************/
void timer0() interrupt 1
{
TH0=0XFC;//1ms
TL0=0X66;
UartRxMonitor(1); //串口接收監控
KeyRead(); //按鍵掃描
js++;
if(js==200){ba=1;js=0;} //200ms采集一次溫度數據
if(sd==1){js1++;if(js1==2000){js1=0;kk=1;}}//主動模式發送模式2s發送一次溫度數據
if(sd1==1){js2++;if(js2==1000){js2=0;kk=1;}}//超設定值發送模式1s發送一次溫度數據
if(bz2==1){js3++;if(js3==300){z=1;smg2=5;bz3=1;}if(js3==600){z=0;smg2=0;js3=0;}}//數碼管閃爍
if(z==0)
{
smg2++;
}else{
smg2=y;//讓逐個顯示位
}
switch(smg2){ //數碼管掃描
/**************數碼管-開始*****************/
case 1: P1=seg7code[ge];L3=1;L2=1;L1=0;dp=0;break;//從P2進P0出
case 2: P1=seg7code[shi];L3=1;L2=0;L1=1;dp=0;break;
case 3: P1=seg7code[bai]; L3=0;L2=1;L1=1;dp=0;break;
/**************數碼管-結束*****************/
default: smg2=0; L3=1;L2=1;L1=1; break;
}
}
/********************************************************************
主函數
*********************************************************************/
void main()
{
hz=0xFE;lz=0xE0; //9600
ConfigTimer0(); //定時器初始化
ConfigUART();
InitADC(); //AD初始化
P1M0 = 0xff; //設置強推挽和開漏模式
P1M1 = 0x80;
P3M0 = 0x08; //小數點使用
P3M1 = 0x00;
if(Byte_Read(0X0001)==0xff){ss=0;s1=0;s2=0;}//首次讀取,如果讀到0xFF說明沒有存過數據,直接付給00值
else
{
ss=Byte_Read(0X0001);//板子地址
s1=Byte_Read(0X0002);//按鍵設定值
s2=Byte_Read(0X0003);//按鍵設定值
}
s2=s2*10;
s=s2+s1; //按鍵設定值
while(1)
{
if((btv_1 == 0)&&(btv_2 == 0)&&(bb_1 == 0)){hz=0xFF;lz=0x70;ConfigUART();bb_1=1;bb_2=0;bb_3=0;bb_4=0;} //波特率設置兩個撥碼開關撥上去19200
if((btv_1 == 0)&&(btv_2 == 1)&&(bb_2 == 0)){hz=0xFB;lz=0x80;ConfigUART();bb_1=0;bb_2=1;bb_3=0;bb_4=0;} //波特率設置2400
if((btv_1 == 1)&&(btv_2 == 0)&&(bb_3 == 0)){hz=0xFD;lz=0xC0;ConfigUART();bb_1=0;bb_2=0;bb_3=1;bb_4=0;} //波特率設置4800
if((btv_1 == 1)&&(btv_2 == 1)&&(bb_4 == 0)){hz=0xFE;lz=0xE0;ConfigUART();bb_1=0;bb_2=0;bb_3=0;bb_4=1;} //波特率設置都不撥 9600
if(ba==1){dat=((ADCRead(7)*51)/255);dat1=dat*100/249;ba=0;} //51是單片機的工作電壓,單片機的工作電壓是多少這個就是多少
if((y==0)&&(z==0)){led(dat1);} //zs標志位控制小數點
if(y==1){zs=0;led(s1);}
if(y==2){zs=0;led(s2);}
if(y==3){zs=0;z=0;led(s);} //顯示設定時間
if(dat1>s){sd1=1;bz=1;bz2=1;}else{sd1=0;bz=0;bz2=0;}//當溫度超過設定溫度時主動發送電流數據
if((bz2==0)&&(bz3==1)){z=0;bz3=0;} //bz3防止數碼閃爍后變黑不亮標志位
if((zc==0)&&(bz==0)){sd=1;}else{sd=0;} //主從模式
key_1();
key_2();
UartDriver();
if(kk==1)
{
unsigned char len;
xdata unsigned char buf[10];
HexToDec(dat1); //16進制轉10進制
dat3 = h_1*16+l_1;
h_1=0;l_1=0;
HexToHex(dat3);
dat4 = h_2|l_2;//10進制轉16進制
h_2=0;l_2=0;
buf[0]=0xAA; //起始位
buf[1]=ss; //地址位
buf[2]=0x06; //功能位
buf[3]=dat4; //電流值
buf[4]=0xBB; //結束位
len=5;
UartWrite(buf,len);
kk=0;
}
if(k==1) //存儲板子地址
{
Sector_Erase(0);
Byte_Program(0x0001,ss); //寫入扇區
Byte_Program(0x0002,s1); //寫入扇區
Byte_Program(0x0003,(s2/10)); //寫入扇區
k=0;
}
}
}
/*******************************************************************
* 串口讀,寫
********************************************************************/
void InterruptUART() interrupt 4 //UART中斷服務函數
{
if (RI) //接收到字節
{
RI = 0; //手動清零接收中斷標志位
if (cntRxd < sizeof(bufRxd)) //接收緩沖區尚未用完時,
{
bufRxd[cntRxd++] = SBUF; //保存接收字節,并遞增計數器
}
}
if (TI) //字節發送完畢
{
TI = 0; //手動清零發送中斷標志位
flagOnceTxd = 1; //設置單次發送完成標志
}
}
unsigned char UartRead(unsigned char *buf, unsigned char len) //串口數據讀取函數,數據接收指針buf,讀取數據長度len,返回值為實際讀取到的數據長度
{
unsigned char i=0;
if (len > cntRxd) //讀取長度大于接收到的數據長度時,
{
len = cntRxd; //讀取長度設置為實際接收到的數據長度
}
for (i=0; i<len; i++) //拷貝接收到的數據
{
*buf = bufRxd[ i];
buf++;
}
cntRxd = 0; //清零接收計數器
return len; //返回實際讀取長度
}
void UartWrite(unsigned char *buf, unsigned char len) //串口數據寫入函數,即串口發送函數,待發送數據指針buf,數據長度len
{
while (len--) //發送數據
{
flagOnceTxd = 0;
SBUF = *buf;
buf++;
while (!flagOnceTxd);
}
}
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;
}
}
//讀一字節,調用前需打開IAP 功能,入口:DPTR = 字節地址,返回:A = 讀出字節
INT8U Byte_Read(INT16U add)
{
IAP_DATA = 0x00;
IAP_CONTR = ENABLE_ISP; //打開IAP 功能, 設置Flash 操作等待時間
IAP_CMD = 0x01; //IAP/ISP/EEPROM 字節讀命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //設置目標單元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //設置目標單元地址的低8 位地址
//EA = 0;
IAP_TRIG = WD1; //先送 WD1,再送WD2 到ISP/IAP 觸發寄存器,每次都需如此
IAP_TRIG = WD2; //送完WD2 后,ISP/IAP 命令立即被觸發起動
_nop_();
//EA = 1;
IAP_Disable(); //關閉IAP 功能, 清相關的特殊功能寄存器,使CPU 處于安全狀態,
//一次連續的IAP 操作完成之后建議關閉IAP 功能,不需要每次都關
return (IAP_DATA);
}
/*********************************************************************************************/
//字節編程,調用前需打開IAP 功能,入口:DPTR = 字節地址, A= 須編程字節的數據
void Byte_Program(INT16U add, INT8U ch)
{
IAP_CONTR = ENABLE_ISP; //打開 IAP 功能, 設置Flash 操作等待時間
IAP_CMD = 0x02; //IAP/ISP/EEPROM 字節編程命令
my_unTemp16.un_temp16 = add;
IAP_ADDRH = my_unTemp16.un_temp8[0]; //設置目標單元地址的高8 位地址
IAP_ADDRL = my_unTemp16.un_temp8[1]; //設置目標單元地址的低8 位地址
IAP_DATA = ch; //要編程的數據先送進IAP_DATA 寄存器
//EA = 0;
IAP_TRIG = WD1; //先送 WD1,再送WD2 到ISP/IAP 觸發寄存器,每次都需如此
IAP_TRIG = WD2; //送完WD2 后,ISP/IAP 命令立即被觸發起動
_nop_();
//EA = 1;
IAP_Disable(); //關閉IAP 功能, 清相關的特殊功能寄存器,使CPU 處于安全狀態,
//一次連續的IAP 操作完成之后建議關閉IAP 功能,不需要每次都關
}
/*********************************************************************************************
//擦除扇區, 入口:DPTR = 扇區地址 */
void Sector_Erase(uint addr)
{
IAP_CONTR = ENABLE_ISP; //打開IAP 功能, 設置Flash 操作等待時間
IAP_CMD = 3; //IAP/ISP/EEPROM 扇區擦除命令
// my_unTemp16.un_temp16 = add;
IAP_ADDRH = addr>>8; //設置目標單元地址的高8 位地址
IAP_ADDRL = addr; //設置目標單元地址的低8 位地址
IAP_TRIG = 0x5a; //先送 WD1,再送WD2 到ISP/IAP 觸發寄存器,每次都需如此
IAP_TRIG = 0xa5; //送完WD2 后,ISP/IAP 命令立即被觸發起動
_nop_();
//EA = 1;
IAP_Disable(); //關閉IAP 功能, 清相關的特殊功能寄存器,使CPU 處于安全狀態,
//一次連續的IAP 操作完成之后建議關閉IAP 功能,不需要每次都關
}
/*********************************************************************************************/
void IAP_Disable()
{
//關閉IAP 功能, 清相關的特殊功能寄存器,使CPU 處于安全狀態,
//一次連續的IAP 操作完成之后建議關閉IAP 功能,不需要每次都關
IAP_CONTR = 0; //關閉IAP 功能
IAP_CMD = 0; //清命令寄存器,使命令寄存器無命令,此句可不用
IAP_TRIG = 0; //清命令觸發寄存器,使命令觸發寄存器無觸發,此句可不用
IAP_ADDRH = 0x80;
IAP_ADDRL = 0;
}
/*********************************************************************************************/
|
|