STC8H单片机利用 ADC 第 15 通道测量外部电压或电池电压

 STC8H 系列 ADC 的第 15 通道用于测量内部参考信号源,由于内部参考信号源很稳定,约为 1.19V, 且不会随芯片的工作电压的改变而变化,所以可以通过测量内部 1.19V 参考信号源,然后通过 ADC 的 值便可反推出外部电压或外部电池电压。以下是如何设置和读取 ADC 第 15 通道的详细步骤:

1. 硬件连接

确保你要测量的电压信号(如外部电压或电池电压)通过适当的电路连接到 ADC 输入引脚。对于 STC8H 单片机,ADC 第 15 通道通常连接到外部电压输入引脚。

2. 配置 ADC

2.1 启用 ADC 功能

首先,你需要在单片机的初始化代码中启用 ADC 功能。通常在 STC8H 系列单片机中,这涉及到设置相关的寄存器

// 假设使用 STC8H 的标准库函数或自定义函数
void ADC_Init(void) {
    // 使能 ADC 模块
    ADCCFG |= 0x01;  // 开启 ADC 功能,具体寄存器设置请查阅数据手册
}
2.2 配置 ADC 输入通道

选择 ADC 第 15 通道作为输入源。通常可以通过设置 ADC 通道选择寄存器来完成这一操作。

void ADC_SetChannel(uint8_t channel) {
    // 选择 ADC 通道
    ADCCON |= (channel & 0x0F); // 设置通道编号,具体寄存器设置请查阅数据手册
}
2.3 配置 ADC 转换参数

设置 ADC 的采样精度、参考电压等参数,以确保测量精度和范围。

void ADC_Config(void) {
    ADCCON |= 0x40; // 设置为 12 位分辨率,具体设置请查阅数据手册
}

3. 启动 ADC 转换

启动 ADC 转换并等待转换完成。ADC 转换可以通过软件触发,也可以通过硬件触发。以下是软件触发的例子:

uint16_t ADC_Read(void) {
    // 启动 ADC 转换
    ADCCON |= 0x80; // 开始转换,具体寄存器设置请查阅数据手册

    // 等待转换完成
    while (!(ADCCON & 0x08)); // 等待完成标志位,具体设置请查阅数据手册

    // 读取结果
    uint16_t result = (ADCH << 8) | ADCL; // 读取结果寄存器,具体寄存器设置请查阅数据手册
    return result;
}

4. 计算实际电压

ADC 输出值需要转换成实际电压值。计算电压值的公式通常是:

5. 完整示例代码

uart.h


#ifndef _UART_H_
#define _UART_H_

#include "system.h"

//===== 串口使能 ===========
#define U1_ENABLE

#define UART_SBUF_LEN   32
#define UART_RBUF_LEN   32

#define _Debug_  				0         //调试模式设置  1开启调试模式  0关闭调试模式
#if _Debug_
#define Debug   printf       
#else
#define Debug  /##/
#endif


#define PRINTF_SEL 1

typedef struct 
{
    u8 rBuf[UART_RBUF_LEN];
    u16 rCnt;
    bool_t rOver;
}
Usart_Read_STR;



extern idata Usart_Read_STR U1_rSTR;
extern u8 U1_sBusy_Flag;

//extern u16  U1_swithcTime;



void Uart1_Init(u32 baud);
void Uart1_Send_Byte(u8 byte);
void Uart1_Send_Str(u8 *string);
void Uart1_Send_xStr(u8 *string,u16 x);


void down_load(u8 *RxBufer);

void CleanBufer(uint8 *ptr,uint16 Size);



/**********************************
* 系统时钟中断服务程序
* 根据定时器编号更改中断入口
* 定时器0 -- 1
* 定时器1 -- 3
**********************************/
extern void Check_U1_rOver(void);


#endif

uart.c


#include "uart.h"

u8 Uart_sBuf[UART_SBUF_LEN];    //串口共用发送缓存


/**********************************************************
* 串口1相关函数
*/
#ifdef U1_ENABLE

u8 U1_sBusy_Flag = 0;           //串口1发送忙碌
idata Usart_Read_STR U1_rSTR;   //串口1接收缓存

//u16  U1_swithcTime=0;

/*----------------------------
* 初始化串口1
* ch:串口引脚映射通道
* 0:P3.0/RxD, P3.1/TxD
* 1:P3.6/RxD_2, P3.7/TxD_2
* 2:P1.6/RxD_3, P1.7/TxD_3

* 注意STC15W408AS无定时器1
----------------------------*/
#define U1_BAUD 9600
#define S1_S0 0x40              //P_SW1.6
#define S1_S1 0x80              //P_SW1.7

void Uart1_Init(u32 baud)
{
    
	ACC = P_SW1;
	ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=0
	P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)


    SCON = 0x50;                            //8位可变波特率
    T2L = (65536 - (MAIN_Fosc/4/baud));       //设置波特率重装值
    T2H = (65536 - (MAIN_Fosc/4/baud))>>8;
     
    AUXR |= 0x15;   //T2为1T模式,启动定时器2,选择定时器2为串口1的波特率发生器
    ES = 1;         //使能串口1中断
    EA = 1;
}

/*----------------------------
* 串口发送1个字节
----------------------------*/
void Uart1_Send_Byte(u8 byte)
{
    U1_sBusy_Flag = 1;
    SBUF = byte;
    while(U1_sBusy_Flag);
}

/*----------------------------
* 串口发送字符串
----------------------------*/
void Uart1_Send_Str(u8 *string)
{
	while(*string != 0)
    {
        U1_sBusy_Flag = 1;
        SBUF = *string++;
        while(U1_sBusy_Flag);
    }
	
}

/*----------------------------
* 串口发送指定长度字符串
----------------------------*/
void Uart1_Send_xStr(u8 *string,u16 x)
{
	while(x--)
    {
        U1_sBusy_Flag = 1;
        SBUF = *string++;
        while(U1_sBusy_Flag);
    }
	
}



/************************************* Printf 函数 **********************************************************

通过查阅资料,51 单片机 通过 printf 打印格式化数据的时候,不能使用 %d 之类的占位符,转而使用以下占位符:

待打印数据的大小        格式化的符号        备注
占位符 8位        bd/bu        bd:有符号8位数据 bu:无符号8位数据
占位符 16位        hd/hu        hd:有符号16位数据 hu:无符号16位数据
占位符 32位        ld/lu        ld:有符号32位数据 lu:无符号32位数据



  char a = 1;
  int b  = 12365;
  long c = 0x7FFFFFFF;

  unsigned char x = 'A';
  unsigned int y  = 54321;
  unsigned long z = 0x4A6F6E00;

  float f = 10.0;
  float g = 22.95;

printf ("char %bd int %d long %ld\n",a,b,c);
printf ("Uchar %bu Uint %u Ulong %lu\n",x,y,z);
printf ("xchar %bx xint %x xlong %lx\n",x,y,z);  //16进制显示
printf ("String %s is at address %p\n",buf,p);
printf ("%f != %g\n", f, g);
printf ("%*f != %*g\n", (int)8, f, (int)8, g);

***********************************************************************************************************************/
#if(PRINTF_SEL == 1)

char putchar(char c)
{
	Uart1_Send_Byte(c);
	return c;
}

#elif(PRINTF_SEL == 2)

char putchar(char c)
{
	UART2_Send_byte(c);
	return c;
}

#elif(PRINTF_SEL == 3)

char putchar(char c)
{
	UART_Send_byte(UART3,c);
	return c;
}

#elif(PRINTF_SEL == 4)

char putchar(char c)
{
	UART_Send_byte(UART4,c);
	return c;
}

#endif

#endif




main.c

#include "STC8.h"  
#include "Headers.h"

#define MAIN_Fosc		24000000L	//定义主时钟
/========================================================================
// 函数: void delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2022-6-3
// 备注: 
//========================================================================
void delay_ms(int ms)
{
    u16 i;
    do{
        i = MAIN_Fosc / 10000;
        while(--i);   //10T per loop
    }while(--ms);
}

void ADCInit() 
{ 
	ADCTIM = 0x3f;		//设置 ADC 内部时序,ADC采样时间建议设最大值
    ADCCFG = 0x2f;		//设置 ADC 时钟为系统时钟/2/16
    ADC_CONTR = 0x80; //使能 ADC 模块
}
 
u16 ADCRead(int channel) 
{ 
	 ADC_RES = 0;
    ADC_RESL = 0;

    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    while((ADC_CONTR & 0x20) == 0)  ;   //wait for ADC finish
    ADC_CONTR &= ~0x20;     //清除ADC结束标志
    return  (((u16)ADC_RES << 8) | ADC_RESL);
}


void main(void)
{
    float vcc=0.00;
	u16 res;
	u8 i;
    Uart1_Init(9600);	//9600bps@24.000MHz
    ADCInit();

    while(1)
    {
        ADCRead(15);  
		ADCRead(15); //前两个数据建议丢弃 
		res = 0; 
		for (i=0; i<8; i++) 
		{
			res += ADCRead(15); //读取 8 次数据 
		} 
		res >>= 3; //取平均值 
		
		vcc = (4096L * 1.19 / res); //(12 位 ADC 算法)计算 VREF 管脚电压,即电池电压 
		
		printf("ADC_convert:%g mV \r\n",  vcc);
		
		delay_ms(500);
    }

}

6、测试结果

由于没有读取内部基准电压结果会有一点小误差。实际值2.76V,ADC测量的外部电压为2.79V。需要更高精度的可以把1.19换成 ,读取内部 1.19V 参考信号源-BGV 值。具体可以研究一下手册

7. 注意事项

  • 确保参考电压稳定并且准确,以获得准确的测量结果。
  • 根据实际硬件连接情况,可能需要对 ADC 引脚进行适当的电平转换或缓冲处理。
  • 检查 STC8H 单片机的数据手册以确认寄存器设置和通道配置的具体细节,因为不同型号的 STC8H 可能有不同的寄存器设置。

以上是如何使用 STC8H 单片机的 ADC 第 15 通道测量外部电压或电池电压的详细步骤。如果有进一步的问题或需要更多的帮助,请随时询问!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值