- 打卡等级:初来乍到
- 打卡总天数:1
- 最近打卡:2025-03-17 16:39:04
中级会员
- 积分
- 253
|
本帖最后由 钰平电子 于 2023-6-29 13:43 编辑
#include <STC12C5A60S2.H>
#include <intrins.h>
/****************************模拟量开始*********************************************/
#define ADC_POWER 0x80 //ADC 电源控制位
#define ADC_FLAG 0x10 //ADC 转换结束标志位
#define ADC_START 0x08 //ADC 开始转换控制位
#define ADC_SPEEDLL 0x00 //420 个时钟周期转换一次
#define ADC_SPEEDL 0x20 //280 个时钟周期转换一次
#define ADC_SPEEDH 0x40 //140 个时钟周期转换一次
#define ADC_SPEEDHH 0x60 //70 个时钟周期转换一次
/******************************模拟量结束*******************************************/
#define uchar unsigned char//宏定义无符号字符型
#define uint unsigned int //宏定义无符号整型
void InitADC();
uint GetADCResult(uchar px);
void Selectsort(uint A[],uchar n) ;//冒泡函数
uint volt; //最终数据保存变量
uint Rs=0,Rs1=0;
long ad;
uint Temp[8],ad1;
uint adnum=4;
uint xdata adcj[128]; //保存测量的数据 做冒泡处理
uchar j = 0; //冒泡程序选择的最多数据个数
uint xdata TempH_Tab[] = {
3251,3094,2945,2804,2670,2543,2422,2307,2199,2095,1997,1904,1816,1732,1652,1577,1505,1437,1372,1310,//0~19
1252,1196,1143,1093,1045,1000,956 ,915 ,876 ,839 ,803 ,770 ,737 ,707 ,678 ,650 ,623 ,598 ,574 ,551 ,//20~39
529 ,508 ,488 ,469 ,450 ,433 ,416 ,400 ,385 ,370 ,357 ,343 ,330 ,318 ,306 ,295 ,284 ,274 ,264 ,255 ,//40~59
246 ,237 ,228 ,220 ,213 ,205 ,198 ,191 ,185 ,178 ,172 ,167 ,161 ,165 ,150 ,145 ,141 ,136 ,131 ,127 ,//60~79
123 ,119 ,115 ,111 ,108 ,104 ,101 ,98 ,95 ,92 ,89 ,86 ,83 ,81 ,78 ,76 ,73 ,71 ,69 ,67 ,//80~99
65 ,63 ,61 ,59 ,58 ,56 ,54 ,53 ,51 ,50 ,48 ,47 ,46 ,44 ,43 ,42 ,41 ,40 ,39 ,38 ,//100~119
37 ,36//120 121
};
uint Get_Temp(uint dat); // 获得温度数据
unsigned char T0RH = 0; //T0重载值的高字节
unsigned char T0RL = 0; //T0重载值的低字节
bit flagFrame = 0; //帧接收完成标志,即接收到一帧新数据
bit flagTxd = 0; //单字节发送完成标志,用来替代TXD中断标志位
unsigned char cntRxd = 0; //接收字节计数器
unsigned char pdata bufRxd[100]; //接收字节缓冲区
void UartDriver();//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
void UartAction(unsigned char *buf, unsigned char len);//在接收到的数据帧后添加换车换行符后发回
void UartWrite(unsigned char *buf, unsigned char len);//串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度
unsigned char UartRead(unsigned char *buf, unsigned char len);//串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度
void UartRxMonitor(unsigned char ms);//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
void ConfigUART(unsigned int baud);//串口配置函数,baud-通信波特率
void ConfigTimer0(unsigned int ms);//配置并启动T0,ms-T0定时时间
uchar Byte_Read(uint add); //读一字节,调用前需打开IAP 功能
void Byte_Program(uint add, uint ch); //字节编程,调用前需打开IAP 功能
void Sector_Erase(uint add); //擦除扇区
void IAP_Disable(); //关闭IAP 功能
void PowerStorage();
void Delay();
#define ENABLE_ISP 0x81 //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值
sbit out01=P2^1;
sbit out02=P2^2;
sbit out03=P2^3;
sbit out04=P2^4;
uint upperlimit[4]={0xff,0xff,0xff,0xff};//上限
uint returndifference[4]={0xff,0xff,0xff,0xff};//回差值
void UartAction(unsigned char *buf, unsigned char len){//在接收到的数据帧后添加换车换行符后发回
if((len==7)&&(buf[0]==0xAA)&&(buf[6]==0xBB)){
if((buf[1]==0x06)&&(buf[2]==0x00)&&(buf[3]==0x00)&&(buf[4]==0x00)&&(buf[5]==0x00)){//温度查询
buf[0]=0xcc;
buf[1]=0x06;
buf[2]=Temp[4];//第一路温度
buf[3]=Temp[5];//第二路温度
buf[4]=Temp[6];//第三路温度
buf[5]=Temp[7];//第四路温度
buf[6]=0xdd;
len=7;
UartWrite(buf, len);
}
if((buf[1]==0x07)&&(buf[2]==0x00)&&(buf[3]==0x00)&&(buf[4]==0x00)&&(buf[5]==0x00)){//上限查询
buf[0]=0xcc;
buf[1]=0x07;
buf[2]=upperlimit[0];//第一路温度
buf[3]=upperlimit[1];//第二路温度
buf[4]=upperlimit[2];//第三路温度
buf[5]=upperlimit[3];//第四路温度
buf[6]=0xdd;
len=7;
UartWrite(buf, len);
}
if((buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x00)&&(buf[4]==0x00)&&(buf[5]==0x00)){//回差值查询
buf[0]=0xcc;
buf[1]=0x08;
buf[2]=returndifference[0];//第一路温度
buf[3]=returndifference[1];//第二路温度
buf[4]=returndifference[2];//第三路温度
buf[5]=returndifference[3];//第四路温度
buf[6]=0xdd;
len=7;
UartWrite(buf, len);
}
if((buf[1]==0x09)&&(buf[4]==0x00)&&(buf[5]==0x00)){//上限设置
if((buf[2]>=0x01)&&(buf[2]<=0x04)){
if(buf[3]<0x79){
if(buf[2]==0x01){upperlimit[0]=buf[3];buf[3]=upperlimit[0];buf[2]=0x01;}
else if(buf[2]==0x02){upperlimit[1]=buf[3];buf[3]=upperlimit[1];buf[2]=0x02;}
else if(buf[2]==0x03){upperlimit[2]=buf[3];buf[3]=upperlimit[2];buf[2]=0x03;}
else if(buf[2]==0x04){upperlimit[3]=buf[3];buf[3]=upperlimit[3];buf[2]=0x04;}
}else{//数据超过范围
buf[3]=0xff;
if(buf[2]==0x01){buf[2]=0x01;upperlimit[0]=0xff;}
else if(buf[2]==0x02){buf[2]=0x02;upperlimit[1]=0xff;}
else if(buf[2]==0x03){buf[2]=0x03;upperlimit[2]=0xff;}
else if(buf[2]==0x04){buf[2]=0x04;upperlimit[3]=0xff;}
}
PowerStorage();
}else{//没有找到地址
buf[2]=0xff;
buf[3]=0xff;
}
buf[0]=0xcc;
buf[1]=0x09;
buf[4]=0;
buf[5]=0;
buf[6]=0xdd;
len=7;
UartWrite(buf, len);
}
if((buf[1]==0x0A)&&(buf[4]==0x00)&&(buf[5]==0x00)){//回差设置
if((buf[2]>=0x01)&&(buf[2]<=0x04)){//在指定的工作路数
if(buf[3]<0x79){//回差值最大不能大于120度
if(buf[2]==0x01){//工作在第一路
//上限-回差值>=0并且上限是有效的
if(((upperlimit[0]-buf[3])<0x78)&&(upperlimit[0]!=0xff)){
returndifference[0]=buf[3];
buf[3]=returndifference[0];
buf[2]=0x01;
buf[4]=0x00;
}else{
buf[4]=0xFF;
buf[3]=0xff;
buf[2]=0x01;
}
}else if(buf[2]==0x02){if(((upperlimit[1]-buf[3])<0x78)&&(upperlimit[1]!=0xff)){
returndifference[1]=buf[3];buf[3]=returndifference[1];buf[2]=0x02;buf[4]=0x00;}else{buf[4]=0xFF;buf[3]=0xff;buf[2]=0x02;}
}else if(buf[2]==0x03){if(((upperlimit[2]-buf[3])<0x78)&&(upperlimit[2]!=0xff)){
returndifference[2]=buf[3];buf[3]=returndifference[2];buf[2]=0x03;buf[4]=0x00;}else{buf[4]=0xFF;buf[3]=0xff;buf[2]=0x03;}
}else if(buf[2]==0x04){if(((upperlimit[3]-buf[3])<0x78)&&(upperlimit[3]!=0xff)){
returndifference[3]=buf[3];buf[3]=returndifference[3];buf[2]=0x04;buf[4]=0x00;}else{buf[4]=0xFF;buf[3]=0xff;buf[2]=0x04;}
}
PowerStorage();
}else{//数据超过范围
buf[3]=0xff;
buf[4]=0xFF;
if(buf[2]==0x01){buf[2]=0x01;}
else if(buf[2]==0x02){buf[2]=0x02;}
else if(buf[2]==0x03){buf[2]=0x03;}
else if(buf[2]==0x04){buf[2]=0x04;}
}
}else{//没有找到地址
buf[2]=0xff;
buf[3]=0xff;
}
buf[0]=0xcc;
buf[1]=0x0A;
buf[5]=0;
buf[6]=0xdd;
len=7;
UartWrite(buf, len);
}
}
}
void main(){
P0M1=0x00;
P0M0=0xff;
InitADC(); //AD转换初始化
EA = 1; //开总中断
ConfigTimer0(1); //配置T0定时1ms
ConfigUART(9600); //配置波特率为9600
upperlimit[0]=Byte_Read(0x01);//掉电存储用到
upperlimit[1]=Byte_Read(0x02);//掉电存储用到
upperlimit[2]=Byte_Read(0x03);//掉电存储用到
upperlimit[3]=Byte_Read(0x04);//掉电存储用到
returndifference[0]=Byte_Read(0x05);//掉电存储用到
returndifference[1]=Byte_Read(0x06);//掉电存储用到
returndifference[2]=Byte_Read(0x07);//掉电存储用到
returndifference[3]=Byte_Read(0x08);//掉电存储用到
while(1){
ad =GetADCResult(adnum); //选择是用p几口做测量 把测量的数据保存在ad1中
adcj[j++]=ad; //把测量的结果在 放到adcj中排序 输出
if(j>128){ //取128个值做处理
j=0;
Selectsort(adcj,128); //冒泡函数 取最稳定的值
ad =adcj[64];
ad1 = (100*ad)/(255-ad);//转换求测量值
if(ad1>=36&&ad1<=3251){//121 0
Temp[adnum]= Get_Temp(ad1)/10; // 温度转换 ;
}else{
Temp[adnum]=255;
}
adnum++;//数码管的位
if(adnum==8){//当位到7则置位0
adnum=4;
}
}
UartDriver(); //调用串口动
}
}
void PowerStorage(){
Sector_Erase(0);
Byte_Program(0x01,upperlimit[0]);
Byte_Program(0x02,upperlimit[1]);
Byte_Program(0x03,upperlimit[2]);
Byte_Program(0x04,upperlimit[3]);
Byte_Program(0x05,returndifference[0]);
Byte_Program(0x06,returndifference[1]);
Byte_Program(0x07,returndifference[2]);
Byte_Program(0x08,returndifference[3]);
}
void InterruptTimer0() interrupt 1{//T0中断服务函数,执行串口接收监控
TH0 = T0RH; //重新加载重载值
TL0 = T0RL;
UartRxMonitor(1); //串口接收监控
}
void InterruptUART() interrupt 4{//串口中断服务函数
if (RI) { //接收到新字节
RI = 0; //清零接收中断标志位
if (cntRxd < sizeof(bufRxd)) {//接收缓冲区尚未用完时,保存接收字节,并递增计数器
bufRxd[cntRxd++] = SBUF; // cntRxd++这个很重要,一开始 cntRxd < sizeof(bufRxd)当进入函数的次数增加,cntRxd慢慢变大,当传入的数据不满的时候就 用时间检测,判断是否是传输完成
}
}
if (TI) { //字节发送完毕
TI = 0; //清零发送中断标志位
flagTxd = 1; //设置字节发送完成标志
}
}
void ConfigTimer0(unsigned int ms){//配置并启动T0,ms-T0定时时间
unsigned long tmp; //临时变量
tmp = 11059200 / 12; //定时器计数频率
tmp = (tmp * ms) / 1000; //计算所需的计数值
tmp = 65536 - tmp; //计算定时器重载值
tmp = tmp + 33; //补偿中断响应延时造成的误差
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 ConfigUART(unsigned int baud){//串口配置函数,baud-通信波特率
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
}
void UartWrite(unsigned char *buf, unsigned char len){//串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度
while (len--){ //循环发送所有字节
flagTxd = 0; //清零发送标志
SBUF = *buf++; //发送一个字节数据
while (!flagTxd); //等待该字节发送完成
}
}
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;
}
cntRxd = 0; //接收计数器清零
return len; //返回实际读取长度
}
void UartDriver(){//串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用
unsigned char len;
unsigned char pdata buf[40];
if (flagFrame){ //有命令到达时,读取处理该命令
flagFrame = 0;
len = UartRead(buf, sizeof(buf)-2); //将接收到的命令读取到缓冲区中
UartAction(buf, len); //传递数据帧,调用动作执行函数
}
}
void UartRxMonitor(unsigned char ms){//串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔
static unsigned char cntbkp = 0;
static unsigned char idletmr = 0;
if (cntRxd > 0){ //接收计数器大于零时,监控总线空闲时间
if (cntbkp != cntRxd){ //接收计数器改变,即刚接收到数据时,清零空闲计时
cntbkp = cntRxd;
idletmr = 0;
}else{ //接收计数器未改变,即总线空闲时,累积空闲时间
if (idletmr < 30){ //空闲计时小于30ms时,持续累加
idletmr += ms;
if (idletmr >= 30){ //空闲时间达到30ms时,即判定为一帧接收完毕
flagFrame = 1; //设置帧接收完成标志
}
}
}
}else{
cntbkp = 0;
}
}
union union_temp16{
uint un_temp16;
uchar un_temp8[2];
}my_unTemp16;
//读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
uchar Byte_Read(uint 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 = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
return (IAP_DATA);
}
//字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
void Byte_Program(uint add, uint 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 = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动
_nop_();
//EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
//擦除扇区, 入口:DPTR = 扇区地址
void Sector_Erase(uint add){
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x03; //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 = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xA5; //送完A5h 后,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 = 0;
IAP_ADDRL = 0;
}
void delay(uint x){//延时程序 0.1秒
uint m,n,s;
for(m=x;m>0;m--)
for(n=20;n>0;n--)
for(s=248;s>0;s--);
}
void InitADC(){// AD转换初始化程序
P1ASF = 0xff; //设置P1口为开漏模式,使用AD功能
ADC_RES = 0; //AD数据寄存器清空
ADC_CONTR = ADC_POWER | ADC_SPEEDLL; //打开AD电源,转换周期420
delay(2); //延时
}
uint GetADCResult(uchar px){ // 10位AD ;
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 Selectsort(uint A[],uchar n){
uchar i,j,min;
uint temp;
for(i=0;i<n;i++) {
min=i;
for(j=i+1;j<=n;j++){ /* 从j往前的数据都是排好的,所以从j开始往下找剩下的元素中最小的 */
if(A[min]>A[j]){ /* 把剩下元素中最小的那个放到A中 */
temp=A;
A=A[j];
A[j]=temp;
}
}
}
}
uint Get_Temp(uint dat){ // 获得温度数据
uchar k=0;
uint tmp=0,buf1,buf2;
while(1){
if(dat<TempH_Tab[k]&&dat>TempH_Tab[k+1]){
buf1=TempH_Tab[k]-dat;
buf2=TempH_Tab[k]-TempH_Tab[k+1];
if(buf2>19){
tmp=k*10+buf1/(buf2/10);
}else{
tmp=k*10+(buf1*10)/buf2;
}
break;
}else if(dat==TempH_Tab[k]){
tmp=k*10;
break;
}
if(k>120)
break;
k++;
}
return tmp;
}
|
|