脑袋空空 发表于 2023-9-7 11:15:28

STC8G1K08A学习方法

各位大佬,有没有什么方法可以看懂单片机的数据手册,里面的内容太抽象了,看前面忘后面。
想实现具体功能,却无从下手,不知道各个寄存器之间的联系。
比如ADC的电压采集,也找不到具体的例子。

angmall 发表于 2023-9-7 12:18:18

就是要看数据手册啊,从这里看起。
你要学 ADC 就看 ADC的章节吧。


点进去就可以看那个章节,然后跟着他的案例程序运行就可以了。




<font size="3">/*
16.6 范例程序
16.6.1 ADC 基本操作(查询方式)
C 语言代码
*/
//测试工作频率为11.0592MHz
#include "reg51.h"
#include "intrins.h"
sfr ADC_CONTR = 0xbc;
sfr ADC_RES = 0xbd;
sfr ADC_RESL = 0xbe;
sfr ADCCFG = 0xde;
sfr P_SW2 = 0xba;
#define ADCTIM (*(unsigned char volatile xdata *)0xfea8)
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xc9;
sfr P5M0 = 0xca;
void main()
{
        P0M0 = 0x00;
        P0M1 = 0x00;
        P1M0 = 0x00;
        P1M1 = 0x00;
        P2M0 = 0x00;
        P2M1 = 0x00;
        P3M0 = 0x00;
        P3M1 = 0x00;
        P4M0 = 0x00;
        P4M1 = 0x00;
        P5M0 = 0x00;
        P5M1 = 0x00;
        P1M0 = 0x00; //设置P1.0 为ADC 口
        P1M1 = 0x01;
        P_SW2 |= 0x80;
        ADCTIM = 0x3f; //设置ADC 内部时序
        P_SW2 &= 0x7f;
        ADCCFG = 0x0f; //设置ADC 时钟为系统时钟/2/16
        ADC_CONTR = 0x80; //使能ADC 模块
        while (1)
        {
                ADC_CONTR |= 0x40; //启动AD 转换
                _nop_();
                _nop_();
                while (!(ADC_CONTR & 0x20)); //查询ADC 完成标志
                ADC_CONTR &= ~0x20; //清完成标志
                P2 = ADC_RES; //读取ADC 结果
                ADCCFG = 0x00; //设置结果左对齐
                ACC = ADC_RES; //A 存储ADC 的10 位结果的高8 位
                B = ADC_RESL; //B存储ADC 的10 位结果的低2 位,B为0
                // ADCCFG = 0x20; //设置结果右对齐
                // ACC = ADC_RES; //A存储ADC 的10 位结果的高2 位,A为0
                // B = ADC_RESL; //B 存储ADC 的10 位结果的低8 位
        }
}

</font>

<font size="3">
/*
16.6.4 利用ADC 第15 通道测量外部电压或电池电压
STC8G 系列ADC 的第15 通道用于测量内部参考信号源,由于内部参考信号源很稳定,约为1.19V,
且不会随芯片的工作电压的改变而变化,所以可以通过测量内部1.19V 参考信号源,然后通过ADC 的
值便可反推出外部电压或外部电池电压。
下图为参考线路图:


C 语言代码
*/

//测试工作频率为11.0592MHz
#include "reg51.h"
#include "intrins.h"
#define FOSC 11059200UL
#define BRT (65536 - FOSC / 115200 / 4)
sfr AUXR = 0x8e;
sfr ADC_CONTR = 0xbc;
sfr ADC_RES = 0xbd;
sfr ADC_RESL = 0xbe;
sfr ADCCFG = 0xde;
sfr P_SW2 = 0xba;
#define ADCTIM (*(unsigned char volatile xdata *)0xfea8)
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xc9;
sfr P5M0 = 0xca;
int *BGV;         //内部1.19V 参考信号源值存放在idata 中
                        //idata 的EFH 地址存放高字节
                        //idata 的F0H 地址存放低字节
                        //电压单位为毫伏(mV)
bit busy;
void UartIsr() interrupt 4
{
        if (TI)
        {
                TI = 0;
                busy = 0;
        }
        if (RI)
        {
                RI = 0;
        }
}
void UartInit()
{
        SCON = 0x50;
        TMOD = 0x00;
        TL1 = BRT;
        TH1 = BRT >> 8;
        TR1 = 1;
        AUXR = 0x40;
        busy = 0;
}
void UartSend(char dat)
{
        while (busy);
        busy = 1;
        SBUF = dat;
}
void ADCInit()
{
        P_SW2 |= 0x80;
        ADCTIM = 0x3f; //设置ADC 内部时序
        P_SW2 &= 0x7f;
        ADCCFG = 0x2f; //设置ADC 时钟为系统时钟/2/16
        ADC_CONTR = 0x8f; //使能ADC 模块,并选择第15 通道
}
int ADCRead()
{
        int res;
        ADC_CONTR |= 0x40; //启动AD 转换
        _nop_();
        _nop_();
        while (!(ADC_CONTR & 0x20)); //查询ADC 完成标志
        ADC_CONTR &= ~0x20; //清完成标志
        res = (ADC_RES << 8) | ADC_RESL; //读取ADC 结果
        return res;
}
void main()
{
        int res;
        int vcc;
        int i;
        P0M0 = 0x00;
        P0M1 = 0x00;
        P1M0 = 0x00;
        P1M1 = 0x00;
        P2M0 = 0x00;
        P2M1 = 0x00;
        P3M0 = 0x00;
        P3M1 = 0x00;
        P4M0 = 0x00;
        P4M1 = 0x00;
        P5M0 = 0x00;
        P5M1 = 0x00;
        BGV = (int idata *)0xef; //内部1.19V 参考信号源值存放在idata 中
        ADCInit(); //ADC 初始化
        UartInit(); //串口初始化
        ES = 1;
        EA = 1;
        // ADCRead();
        // ADCRead(); //前两个数据建议丢弃
        res = 0;
        for (i=0; i<8; i++)
        {
                res += ADCRead(); //读取8 次数据
        }
        res >>= 3; //取平均值
        vcc = (int)(1024L * *BGV / res);    //(10 位ADC 算法)计算VREF 管脚电压,即电池电压
        // vcc = (int)(4096L * *BGV / res); //(12 位ADC 算法)计算VREF 管脚电压,即电池电压
        //注意,此电压的单位为毫伏(mV)
        UartSend(vcc >> 8); //输出电压值到串口
        UartSend(vcc);
        while (1);
}
/*
上面的方法是使用ADC 的第15 通道反推外部电池电压的。在ADC 测量范围内,ADC 的外部测量
电压与ADC 的测量值是成正比例的,所以也可以使用ADC 的第15 通道反推外部通道输入电压,假设
当前已获取了内部参考信号源电压为BGV,内部参考信号源的ADC 测量值为resbg,外部通道输入电压
的ADC 测量值为resx,则外部通道输入电压Vx=BGV / resbg * resx;

*/
</font>








脑袋空空 发表于 2023-9-7 13:19:35

angmall 发表于 2023-9-7 12:18
就是要看数据手册啊,从这里看起。
你要学 ADC 就看 ADC的章节吧。



谢谢,你发的程序有注释说明,所以理解起来要好一点。

脑袋空空 发表于 2023-9-7 13:20:55

市面上不知道有没有类似像大话数据结构这样的书籍,可以通俗易懂的讲解单片机。

wdllmh 发表于 2024-3-10 17:46:47

你好,我使用一枚3s电池,参考上面的代码写出来之后,返回的电压值是5816(mv),而正常电压应该为12000(mv)左右,请问这个程序检测的电压值是有上限的吗

神农鼎 发表于 2024-3-10 18:05:05

先学习下 郭天祥 老师讲的 ADC 部分
然后再看自己用的 MCU 的数据手册,毕竟不完全相同



提高篇10-5-利用STC8H单片机内部1.19V信号源反推电源电压-郭天祥老师-STC单片机教学视频 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)


页: [1]
查看完整版本: STC8G1K08A学习方法