wulin 发表于 2025-9-17 10:42:29

请教STC单片机端口的内置上拉电阻应用问题。

各位大神好:请教STC单片机端口的内置上拉电阻应用问题。使用STC8H1K08-20设计一款共阴数码管显示温度表。P1.0~1.7用作段驱动。预想利用内置上拉电阻代替限流电阻。结果样品出来数码管亮度达不到预期。后在STC8H8K64U实验板上测试,准双向IO口外接300欧负载电阻,测量高电平输出电流0.28mA,使能上拉电阻POPU、使能驱动电流PODR都无效,IO口高电平输出电流依然是0.28mA不变。用户手册中关于上拉电阻介绍只一带而过,也没有应用实例。特此向各位大神请教,谢谢!

小飞侠 发表于 2025-9-17 14:10:27

单片机内部上拉电阻阻值较大,达到几K欧姆,所以电流很小

小飞侠 发表于 2025-9-17 14:12:12

查看数据手册,上拉电阻阻值,3V时为6K左右,5V时4.2K左右

DebugLab 发表于 2025-9-17 15:04:35

驱动数码管建议使用8H4K64TL,80mA大电流IO,硬件自动扫描
上拉电阻可以使用配置工具生成代码



wulin 发表于 2025-9-18 10:13:59

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功能
}

网老四 发表于 2025-9-18 10:56:53

不要轻易怀疑芯片自身问题,遇到异常请仔细阅读产品手册
使用扩展特殊寄存器XFR的读写,需要先开使能 P_SW2 |= 0x80

wulin 发表于 2025-9-18 14:45:32

网老四 发表于 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]
查看完整版本: 请教STC单片机端口的内置上拉电阻应用问题。