请教STC单片机端口的内置上拉电阻应用问题。
各位大神好:请教STC单片机端口的内置上拉电阻应用问题。使用STC8H1K08-20设计一款共阴数码管显示温度表。P1.0~1.7用作段驱动。预想利用内置上拉电阻代替限流电阻。结果样品出来数码管亮度达不到预期。后在STC8H8K64U实验板上测试,准双向IO口外接300欧负载电阻,测量高电平输出电流0.28mA,使能上拉电阻POPU、使能驱动电流PODR都无效,IO口高电平输出电流依然是0.28mA不变。用户手册中关于上拉电阻介绍只一带而过,也没有应用实例。特此向各位大神请教,谢谢!单片机内部上拉电阻阻值较大,达到几K欧姆,所以电流很小 查看数据手册,上拉电阻阻值,3V时为6K左右,5V时4.2K左右 驱动数码管建议使用8H4K64TL,80mA大电流IO,硬件自动扫描
上拉电阻可以使用配置工具生成代码
DebugLab 发表于 2025-9-17 15:04
驱动数码管建议使用8H4K64TL,80mA大电流IO,硬件自动扫描
上拉电阻可以使用配置工具生成代码
按正常设计应该设置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_IAP12 //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;//显示缓存
uintSample; //ADC采样值Sample
bit flag=0; //中断标志
bit Success; //采样完成标志
bit Key_value;//键值
uintThreshold=310;//OUT开关阈值
uintnum;
charError;//误差补偿
// 10K B3950 NTC温阻电压编码表
// 上分压电阻10K AD值放大4倍
uint code T_Value={
// 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操作函数声明*****************************************
voidIapIdle(); //关闭IAP/EEPROM
uchar IapRead(uint addr); //读取EEPROM数据
voidIapProgram(uint addr,uchar dat);//写入EEPROM数据
voidIapErase(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 = 0x79;//显示"E"
dis_buf = 0x00;
dis_buf = 0x00;
dis_buf = 0x00;
}
else
{
for(i=0;i<5;i++) //对分查表
{
M=(L+H)/2;
if(Sample<=T_Value)
L=M-1;//-1消除非整数误差
else H=M+1;//+1消除非整小数误差
}
if(Sample==T_Value)
{
temp=L-31;//-31索引差值
}
else if(Sample==T_Value)
{
temp=H-31;//-31索引差值
}
else //AD值介于数组两个元素之间
{
while(L<=H)
{
L++;
if(Sample<=T_Value && Sample>T_Value)
{
temp=L-31;//-31索引差值
break;
}
}
}
//ADC值换算成温度值
if(temp<0)//低于0度
{
k=10-((T_Value-Sample)*10/(T_Value-T_Value));//小数线性插补放大10倍
temp=~temp; //取反成正数
temp=temp*10+k;//整数放大10倍+已放大10倍的小数
if(temp/1000==0&&temp/100>0)//负温度大于10度,千位显示"-"
{
dis_buf = 0x40;
dis_buf = table;
}
else if(temp/1000==0&&temp/100==0)//负温度小于10度,千位不显示,百位显示"-"
{
dis_buf = 0x00;
dis_buf = 0x40;
}
}
else //0~150度
{
k=(T_Value-Sample)*10/(T_Value-T_Value);//线性插补放大10倍小数
temp=temp*10+k;//整数放大10倍+放大10倍小数
if(temp/1000==0) dis_buf=0x00;//温度小于100度,千位不显示
else dis_buf = table;//显示千位温度值
if(temp/1000==0&&temp/100==0)dis_buf=0x00;//温度小于10度,百位不显示
else dis_buf = table;//显示百位温度值
}
dis_buf = table|0x80;//十位加小数点
dis_buf = table; //个位(小数位)
}
if(temp<Threshold)OUT=0;
if(temp>Threshold)OUT=1;
}
dis_buf = 0x78;//'t'
dis_buf = table;
dis_buf = table|0x80;
dis_buf = table;
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=++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功能
}
不要轻易怀疑芯片自身问题,遇到异常请仔细阅读产品手册
使用扩展特殊寄存器XFR的读写,需要先开使能 P_SW2 |= 0x80
网老四 发表于 2025-9-18 10:56
不要轻易怀疑芯片自身问题,遇到异常请仔细阅读产品手册
使用扩展特殊寄存器XFR的读写,需要先开使能 P_SW2 | ...
确如6楼大神所言,先打开扩展存储器P_SW2 |= 0x80;再使能上拉电阻。数码管亮度正常。后用STC8H1K08在实验板上IO口高电平,负载电阻300欧测试验证:未打开P_SW2开关,P1PU设置无效,输出电流0.015mA,打开P_SW2开关,输出电流1.1mA。由此证明P1PU设置有效,利用内置4K上拉电阻代替限流电阻直接驱动共阴数码管切实可行。实物对比图如下:
页:
[1]