按正常设计应该设置P1推挽模式并串接1K左右限流电阻。之所以想利用内置上拉4K电阻的目的是为了掌握这个功能的应用。在此次试验中数码管的亮度并没有因为使能4.2K上拉电阻有任何变化,测量端口输出电流也没有发生任何变化。也就是无法证明4.2K上拉电阻使能。
- // 数码管显示-30~150度温度计
- // 单片机型号STC8系列
- // 使用芯片内部时钟11.0592MHz
- // 传感器NTC温敏电阻10K B3950
- // 上分压电阻10K
- #include "stc8h.h"
- #include "intrins.h"
- #define uchar unsigned char
- #define uint unsigned int
- #define key_S 5 //宏定义短按(约10ms)
- #define key_L key_S*100 //宏定义长按(约500ms)
- #define key_I key_S*80 //宏定义长按连+/-间隔(约200ms)
- //宏定义ADC的操作命令
- #define ADCTIM (*(unsigned char volatile xdata *)0xfea8)
- #define ADC_POWER 0x80 //ADC power control dit (宏定义ADC电源控制位)1000 0000
- #define ADC_START 0x40 //ADC start control dit (宏定义ADC启动控制位)0100 0000
- #define ADC_FLAG 0x20 //ADC complete flag (宏定义ADC完成标志位) 0010 0000
- #define ADC_EPWMT 0x10 //使能 PWM 实时触发 ADC 0001 0000
- #define ADC_L 3879 //测温下限
- #define ADC_H 76 //测温上限
- //宏定义ISP的操作命令
- #define CMD_IDLE 0 //空闲模式
- #define CMD_READ 1 //IAP字节读命令
- #define CMD_PROGRAM 2 //IAP字节编程命令
- #define CMD_ERASE 3 //IAP扇区擦除命令
- #define ENABLE_IAP 12 //CPU的等待时间
- #define IAP_ADDRESS 0x0000 //测试地址
- //端口定义
- sbit K1 =P3^2;
- sbit K2 =P3^1;
- sbit K3 =P3^0;
- sbit OUT=P5^4;
- //本地变量声明
- uchar code table[]={//共阴数码管段码"0~f-."
- 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
- 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x80};
- uchar data dis_buf[8];//显示缓存
- uint Sample; //ADC采样值Sample
- bit flag=0; //中断标志
- bit Success; //采样完成标志
- bit Key_value;//键值
- uint Threshold=310;//OUT开关阈值
- uint num;
- char Error; //误差补偿
- // 10K B3950 NTC温阻电压编码表
- // 上分压电阻10K AD值放大4倍
- uint code T_Value[183]={
- // ADC值 温度 下标
- 3892 ,// -31 0
- 3879 ,// -30 1
- 3866 ,// -29 2
- 3852 ,// -28 3
- 3837 ,// -27 4
- 3822 ,// -26 5
- 3806 ,// -25 6
- 3790 ,// -24 7
- 3772 ,// -23 8
- 3754 ,// -22 9
- 3735 ,// -21 10
- 3716 ,// -20 11
- 3695 ,// -19 12
- 3674 ,// -18 13
- 3651 ,// -17 14
- 3628 ,// -16 15
- 3604 ,// -15 16
- 3580 ,// -14 17
- 3554 ,// -13 18
- 3527 ,// -12 19
- 3500 ,// -11 20
- 3471 ,// -10 21
- 3442 ,// -9 22
- 3411 ,// -8 23
- 3380 ,// -7 24
- 3348 ,// -6 25
- 3315 ,// -5 26
- 3281 ,// -4 27
- 3247 ,// -3 28
- 3211 ,// -2 29
- 3175 ,// -1 30
- 3138 ,// 0 31
- 3100 ,// 1 32
- 3061 ,// 2 33
- 3022 ,// 3 34
- 2981 ,// 4 35
- 2941 ,// 5 36
- 2900 ,// 6 37
- 2858 ,// 7 38
- 2815 ,// 8 39
- 2772 ,// 9 40
- 2728 ,// 10 41
- 2684 ,// 11 42
- 2641 ,// 12 43
- 2595 ,// 13 44
- 2550 ,// 14 45
- 2505 ,// 15 46
- 2460 ,// 16 47
- 2414 ,// 17 48
- 2368 ,// 18 49
- 2323 ,// 19 50
- 2277 ,// 20 51
- 2231 ,// 21 52
- 2186 ,// 22 53
- 2140 ,// 23 54
- 2095 ,// 24 55
- 2050 ,// 25 56
- 2005 ,// 26 57
- 1961 ,// 27 58
- 1917 ,// 28 59
- 1873 ,// 29 60
- 1830 ,// 30 61
- 1787 ,// 31 62
- 1745 ,// 32 63
- 1702 ,// 33 64
- 1661 ,// 34 65
- 1620 ,// 35 66
- 1580 ,// 36 67
- 1540 ,// 37 68
- 1502 ,// 38 69
- 1463 ,// 39 70
- 1425 ,// 40 71
- 1389 ,// 41 72
- 1352 ,// 42 73
- 1317 ,// 43 74
- 1282 ,// 44 75
- 1247 ,// 45 76
- 1214 ,// 46 77
- 1181 ,// 47 78
- 1149 ,// 48 79
- 1117 ,// 49 80
- 1087 ,// 50 81
- 1057 ,// 51 82
- 1028 ,// 52 83
- 999 ,// 53 84
- 971 ,// 54 85
- 944 ,// 55 86
- 917 ,// 56 87
- 891 ,// 57 88
- 866 ,// 58 89
- 842 ,// 59 90
- 818 ,// 60 91
- 795 ,// 61 92
- 772 ,// 62 93
- 750 ,// 63 94
- 729 ,// 64 95
- 708 ,// 65 96
- 688 ,// 66 97
- 668 ,// 67 98
- 649 ,// 68 99
- 631 ,// 69 100
- 612 ,// 70 101
- 595 ,// 71 102
- 578 ,// 72 103
- 561 ,// 73 104
- 546 ,// 74 105
- 530 ,// 75 106
- 515 ,// 76 107
- 501 ,// 77 108
- 486 ,// 78 109
- 473 ,// 79 110
- 459 ,// 80 111
- 446 ,// 81 112
- 434 ,// 82 113
- 421 ,// 83 114
- 410 ,// 84 115
- 398 ,// 85 116
- 387 ,// 86 117
- 376 ,// 87 118
- 366 ,// 88 119
- 356 ,// 89 120
- 346 ,// 90 121
- 336 ,// 91 122
- 327 ,// 92 123
- 318 ,// 93 124
- 309 ,// 94 125
- 301 ,// 95 126
- 293 ,// 96 127
- 285 ,// 97 128
- 277 ,// 98 129
- 270 ,// 99 130
- 262 ,// 100 131
- 255 ,// 101 132
- 248 ,// 102 133
- 242 ,// 103 134
- 236 ,// 104 135
- 229 ,// 105 136
- 223 ,// 106 137
- 218 ,// 107 138
- 212 ,// 108 139
- 206 ,// 109 140
- 201 ,// 110 141
- 196 ,// 111 142
- 191 ,// 112 143
- 186 ,// 113 144
- 181 ,// 114 145
- 177 ,// 115 146
- 172 ,// 116 147
- 168 ,// 117 148
- 164 ,// 118 149
- 160 ,// 119 150
- 155 ,// 120 151
- 152 ,// 121 152
- 148 ,// 122 153
- 144 ,// 123 154
- 141 ,// 124 155
- 137 ,// 125 156
- 134 ,// 126 157
- 131 ,// 127 158
- 127 ,// 128 159
- 124 ,// 129 160
- 121 ,// 130 161
- 119 ,// 131 162
- 116 ,// 132 163
- 113 ,// 133 164
- 110 ,// 134 165
- 108 ,// 135 166
- 105 ,// 136 167
- 103 ,// 137 168
- 100 ,// 138 169
- 98 ,// 139 170
- 96 ,// 140 171
- 94 ,// 141 172
- 92 ,// 142 173
- 89 ,// 143 174
- 87 ,// 144 175
- 85 ,// 145 176
- 84 ,// 146 177
- 82 ,// 147 178
- 80 ,// 148 179
- 78 ,// 149 180
- 76 ,// 150 181
- 74 // 151 182
- };
- //本地函数声明
- void Init_ADC(); //初始化ADC
- uint Read(uchar ch); //ADC转换
- void LB_ADC(); //ADC滤波
- void display(); //数码管显示
- void delayms(uint z); //延时
- void Timer0Init(); //定时器初始化
- void key_scan(); //按键扫描
- //EEPROM操作函数声明*****************************************
- void IapIdle(); //关闭IAP/EEPROM
- uchar IapRead(uint addr); //读取EEPROM数据
- void IapProgram(uint addr,uchar dat);//写入EEPROM数据
- void IapErase(uint addr); //擦除EEPROM数据
-
- void main()
- {
- int temp;
- uchar i,j,k,L,M,H;
- //端口模式设置
- OUT=0;
- P1PU = 0xff; //P1使能上拉电阻;
- P1M0 = 0x00; P1M1 = 0x00; //P1准双向;
- P3M0 = 0x00; P3M1 = 0x08; //设置P3.3高阻
- P5M0 = 0x10; P5M1 = 0x00; //设置P5.4推挽
- Init_ADC(); //初始化ADC
- Timer0Init(); //定时器初始化
- if(IapRead(IAP_ADDRESS)==0xff) //初次上电,EEPROM没有数据
- {
- IapProgram(IAP_ADDRESS,Threshold>>8);//阈值高8位
- IapProgram(IAP_ADDRESS+1,Threshold);//阈值低8位
- }
- else
- {
- Threshold=IapRead(IAP_ADDRESS)<<8|IapRead(IAP_ADDRESS+1);//读EEPROM保存的阈值数据
- }
- WDT_CONTR = 0x23; //使能看门狗,溢出时间约为0.5s
- while(1)
- {
- if(flag) //查询中断完成标志 2毫秒
- {
- flag=0; //中断完成标志清0
- L=0; //对分查表索引最小值 -31度
- H=182; //对分查表索引最大值 151度
- display(); //数码管显示程序
- if(++j>=10)
- {
- j=0;
- LB_ADC(); //ADC滤波程序
- }
- if(Success) //ADC采样完成
- {
- Success=0; //采样完成标志清0
- if(Sample>ADC_L || Sample<ADC_H)//判断超出测温范围
- {
- dis_buf[0] = 0x79;//显示"E"
- dis_buf[1] = 0x00;
- dis_buf[2] = 0x00;
- dis_buf[3] = 0x00;
- }
- else
- {
- for(i=0;i<5;i++) //对分查表
- {
- M=(L+H)/2;
- if(Sample<=T_Value[M])
- L=M-1;//-1消除非整数误差
- else H=M+1;//+1消除非整小数误差
- }
- if(Sample==T_Value[L])
- {
- temp=L-31;//-31索引差值
- }
- else if(Sample==T_Value[H])
- {
- temp=H-31;//-31索引差值
- }
- else //AD值介于数组两个元素之间
- {
- while(L<=H)
- {
- L++;
- if(Sample<=T_Value[L] && Sample>T_Value[L+1])
- {
- temp=L-31;//-31索引差值
- break;
- }
- }
- }
- //ADC值换算成温度值
- if(temp<0)//低于0度
- {
- k=10-((T_Value[L]-Sample)*10/(T_Value[L]-T_Value[L+1]));//小数线性插补放大10倍
- temp=~temp; //取反成正数
- temp=temp*10+k;//整数放大10倍+已放大10倍的小数
- if(temp/1000==0&&temp/100>0)//负温度大于10度,千位显示"-"
- {
- dis_buf[0] = 0x40;
- dis_buf[1] = table[temp/100%10];
- }
- else if(temp/1000==0&&temp/100==0)//负温度小于10度,千位不显示,百位显示"-"
- {
- dis_buf[0] = 0x00;
- dis_buf[1] = 0x40;
- }
- }
- else //0~150度
- {
- k=(T_Value[L]-Sample)*10/(T_Value[L]-T_Value[L+1]);//线性插补放大10倍小数
- temp=temp*10+k;//整数放大10倍+放大10倍小数
- if(temp/1000==0) dis_buf[0]=0x00;//温度小于100度,千位不显示
- else dis_buf[0] = table[temp/1000%10];//显示千位温度值
- if(temp/1000==0&&temp/100==0)dis_buf[1]=0x00;//温度小于10度,百位不显示
- else dis_buf[1] = table[temp/100%10];//显示百位温度值
- }
- dis_buf[2] = table[temp/10%10]|0x80;//十位加小数点
- dis_buf[3] = table[temp%10]; //个位(小数位)
- }
- if(temp<Threshold)OUT=0;
- if(temp>Threshold)OUT=1;
- }
- dis_buf[4] = 0x78;//'t'
- dis_buf[5] = table[Threshold/100%10];
- dis_buf[6] = table[Threshold/10%10]|0x80;
- dis_buf[7] = table[Threshold%10];
- key_scan();
- if(num>0)
- {
- num--;
- if(num==0)
- {
- Key_value=0;
- IapErase(IAP_ADDRESS); //擦除EEPROM数据
- IapProgram(IAP_ADDRESS,Threshold>>8);//阈值高8位
- IapProgram(IAP_ADDRESS+1,Threshold);//阈值低8位
- }
- }
- }
- WDT_CONTR = 0x33; //清看门狗,否则系统复位
- }
- }
- // 数码管显示程序
- void display()
- {
- static uchar i=0; //分时显示变量
- uchar j;
- P1=0x00; //消隐
- P3&=0x0f; //清位码(P3高4位)
- switch(i) //送位码(P3低4位不变)
- {
- case 0: P3|=0xe0; break;
- case 1: P3|=0xd0; break;
- case 2: P3|=0xb0; break;
- case 3: P3|=0x70; break;
- }
- if(Key_value!=0)j=4;
- else j=0;
- P1=dis_buf[i+j]; //送段码
- i=++i%4;
- }
- // T0中断服务程序
- void Timer0Interrupt() interrupt 1
- {
- flag=1;
- }
- // 延时程序
- void delayms(uint ms)
- {
- uint i;
- do
- {
- i=1106; //STC8
- while(--i);
- }
- while(--ms);
- }
- //定时器T0初始化程序
- void Timer0Init(void) //2毫秒@11.0592MHz
- {
- AUXR |= 0x80; //定时器时钟1T模式
- TMOD &= 0xF0; //设置定时器模式
- TL0 = 0x9A; //设置定时初始值
- TH0 = 0xA9; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0 = 1; //使能定时器0中断
- EA = 1; //开总中断
- }
- // ADC初始化程序
- void Init_ADC()
- { //ADC 控制器 电源 启动 完成 -- 15通道模拟选择位
- //ADC_CONTR B7 B6 B5 B4 B3 B2 B1 B0
- P_SW2 |= 0x80; //打开扩展存储器
- ADCTIM = 0x3f; //设置 ADC 内部时序
- P_SW2 &= 0x7f; //关闭扩展存储器
- ADCCFG = 0x2f; //设置ADC结果右对齐,速度为1/32系统时钟
- ADC_RES=0; //清除ADC_RES存储器以前的结果
- ADC_RESL=0;
- ADC_CONTR=ADC_POWER; //ADC 开启电源
- delayms(1); //上电延时1ms
- }
- //ADC转换程序
- uint Read(uchar CH) //获取ADC结果
- {
- ADC_CONTR=ADC_POWER|ADC_START|CH;//启动转换1100 1000
- _nop_();_nop_(); //小延时
- while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成标志置位 1010 0000
- ADC_CONTR &=~ADC_FLAG; //清完成标志
- return ADC_RES<<8|ADC_RESL; //返回十位ADC结果
- }
- // ADC滤波程序
- void LB_ADC()
- {
- static uint PJZ_ADC=0; //累计40次采样的变量
- static uchar count=0; //计数器变量
- PJZ_ADC += Read(11); //累计40次采样
- count++; //计数器变量自+1
- if(count>=40) //如果计数4次采样
- {
- count=0; //计数器清0
- Sample=PJZ_ADC/10; //获取12位AD值
- PJZ_ADC=0; //采样变量清0
- Success=1; //采样完成
- }
- }
- //按键扫描
- void key_scan()
- {
- static unsigned int time=0;
- if(!K1||!K2||!K3)
- {
- time++;
- if(time>key_L)//长按有效
- time=key_I;//连+/-间隔
-
- if(time==key_S)//短按消抖
- {
- if(!K1)
- {
- Key_value=~Key_value;
- }
- }
- if(time==key_S||time==key_L)//短按消抖或长按连+/-
- {
- if(!K2 && Key_value==1)
- {
- Threshold=Threshold+10;
- }
- if(!K3 && Key_value==1)
- {
- Threshold=Threshold-10;
- }
- }
- if(Key_value==1)
- num=2500;
- else num=1;
- }
- else
- {
- time=0;
- }
- }
-
- //==============EEPROM部分=====================
- // 关闭IAP功能
- void IapIdle()
- {
- IAP_CONTR = 0; //关闭IAP功能
- IAP_CMD = 0; //清除命令寄存器
- IAP_TRIG = 0; //清除触发寄存器
- IAP_ADDRH = 0x80; //将地址设置到非IAP区域
- IAP_ADDRL = 0;
- }
- //从ISP/IAP/EEPROM区域读取一字节
- uchar IapRead(uint addr)
- {
- uchar dat;
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = ENABLE_IAP; //设置等待参数12MHz
- IAP_CMD = CMD_READ; //设置IAP读命令
- IAP_ADDRL = addr; //设置IAP低地址
- IAP_ADDRH = addr >> 8; //设置IAP高地址
- IAP_TRIG = 0x5a; //写触发命令(0x5a)
- IAP_TRIG = 0xa5; //写触发命令(0xa5)
- _nop_(); //小延时
- dat = IAP_DATA; //读IAP数据
- IapIdle(); //关闭IAP功能
- return dat;
- }
- //写一字节数据到ISP/IAP/EEPROM区域
- void IapProgram(uint addr, uchar dat)
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = ENABLE_IAP; //设置等待参数12MHz
- IAP_CMD = CMD_PROGRAM; //设置IAP写命令
- IAP_ADDRL = addr; //设置IAP低地址
- IAP_ADDRH = addr >> 8; //设置IAP高地址
- IAP_DATA = dat; //写IAP数据
- IAP_TRIG = 0x5a; //写触发命令(0x5a)
- IAP_TRIG = 0xa5; //写触发命令(0xa5)
- _nop_(); //小延时
- IapIdle(); //关闭IAP功能
- }
- //ISP/IAP/EEPROM扇区擦除
- void IapErase(uint addr)
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = ENABLE_IAP; //设置等待参数12MHz
- IAP_CMD = CMD_ERASE; //设置IAP擦除命令
- IAP_ADDRL = addr; //设置IAP低地址
- IAP_ADDRH = addr >> 8; //设置IAP高地址
- IAP_TRIG = 0x5a; //写触发命令(0x5a)
- IAP_TRIG = 0xa5; //写触发命令(0xa5)
- _nop_(); //小延时
- IapIdle(); //关闭IAP功能
- }
复制代码
|