数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 3532|回复: 14

[C51] 小白学51单片机,ADC检测电压并显示

[复制链接]
发表于 2024-3-4 11:10:52 | 显示全部楼层 |阅读模式
这几天在学ADC,IC是STC8H8K64U 实际做出来感觉有些不对,
显示15通道(内部1.19V)时,我的显示1.24V



检测通道4,电位器扭到底显示0



电位器往上扭电压会随着增大,但到了4.9以上就显示全是8了,


不知道是哪里处理不对



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
 楼主| 发表于 2024-3-4 11:13:27 | 显示全部楼层
代码如下:

ADC部分:
  1. #include <stc8h.h>
  2. #include "intrins.h"         //_nop_
  3. #include "delayms.h"
  4. typedef unsigned char u8;
  5. typedef unsigned int u16;
  6. u16 voltage;
  7. void adc_init()
  8. {       
  9.         ADCTIM=0x3f;        //0011 1111
  10.         //cssetup ADC通道选择时间0 1个时钟
  11.         //cshold  ADC通道选择保持01 2个时钟
  12.         //smspduty ADC模拟信号采样时间11111 32个时钟
  13.         ADCCFG=        0x2f;        //0010 1111
  14.         //resfmt 转换结果右对齐,B5为1
  15.         //speed  ADC工作时钟1111 sysclk/2/16
  16.         ADC_CONTR=0x80;        //1000 0000
  17.         //adc_power        打开ADC电源B7为1
  18.         delayms(10);                       
  19. }

  20. u16        get_adc12bitresult(u8 channel)
  21. {
  22.         ADC_RES=0;        //
  23.         ADC_RESL=0;        //
  24.         ADC_CONTR=(ADC_CONTR & 0xf0) | 0x40 | channel;        //启动ADC
  25.         //adc_start ADC转换启动0x40 B6为1
  26.         //adc_chs 模拟通道选择
  27.         _nop_();_nop_();_nop_();_nop_();
  28.         while((ADC_CONTR & 0x20)==0);         //等待ADC结束
  29.         //adc_flag 0x20        ADC转换标志B5为1
  30.         ADC_CONTR &= ~0x20;        //标志归0
  31.         return (((u16)ADC_RES<<8) | ADC_RESL);        //高8位左移8位再或上低8位
  32. }

  33. void adc_convert(u8 chn)
  34. {
  35.         u16 j;
  36.         u8 k;
  37.         get_adc12bitresult(chn);        //查询方式做一次ADC,丢弃
  38.         get_adc12bitresult(chn);        //查询方式做一次ADC,丢弃
  39.         for (k=0;k<16;k++)
  40.         j=j+get_adc12bitresult(chn);
  41.         j=j/16;
  42.         voltage=j*0.12207;  //(5/4096)*100
  43. }
复制代码
端口设置部分:
  1. #include <stc8h.h>

  2. void gpio_init()
  3. {
  4.         P_SW2 |= 0x80;        //扩展寄存器XFR访问使能        1000 0000或等于 B7要为1
  5.         P0M1=0x00; P0M0=0x00;        //P0口设置为准双向口 接数码管段选
  6.         P1M1=0x10; P1M0=0x00;        //P1口设置为准双向口 数码管位选P1.4 ADC4
  7.         P5M1=0x00; P5M0=0x00;        //P5口设置为准双向口 P5.2数码管位选
  8. }
复制代码


显示部分:
  1. #include <stc8h.h>
  2. #include "delayms.h"
  3. #include "adc.h"

  4. sbit led_a = P1^0;        //
  5. sbit led_b = P1^1;        //
  6. sbit led_c = P5^2;        //
  7. sbit led_d = P1^3;        //
  8. //数码管接在P0口       
  9. unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x7f};

  10. void display()          //显示函数
  11. {
  12.          P0=table[voltage%10];          //送出段选信号
  13.          led_a=0;                                 //打开个位位选
  14.          delayms(5);
  15.          led_a=1;

  16.          P0=table[voltage/10%10];          //送出段选信号
  17.          led_b=0;                                   //打开十位位选
  18.          delayms(5);
  19.          led_b=1;

  20.          P0=table[voltage/100%10]&table[10];          
  21.          led_c=0;
  22.          delayms(5);
  23.          led_c=1;

  24.          P0=table[voltage/1000%10];         
  25.          led_d=0;
  26.          delayms(5);
  27.          led_d=1;
  28. }
复制代码

主函数部分:
  1. #include <stc8h.h>                //头文件
  2. #include "display.h"
  3. #include "adc.h"
  4. #include "delayms.h"
  5. #include "gpio.h"

  6. void main ()          //主函数
  7. {
  8.         gpio_init();  //初始化
  9.         adc_init();          //初始化
  10.         while(1)
  11.         {
  12.                 adc_convert(4);  //ADC4 P1.4
  13.                 display();         //调用显示函数
  14.         }
  15. }


复制代码




回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-4 14:50:00 | 显示全部楼层
用万用表实测电压也是很接近的,就是为什么扭到最大时不是显示5,怎样让这个显示值更稳定一些?
回复 支持 反对

使用道具 举报

发表于 2024-3-4 18:12:35 | 显示全部楼层
void adc_convert(u8 chn)
{
        u16 j;
        u8 k;
        get_adc12bitresult(chn);        //查询方式做一次ADC,丢弃
        get_adc12bitresult(chn);        //查询方式做一次ADC,丢弃
        for (k=0;k<16;k++)
        j=j+get_adc12bitresult(chn);
        j=j/16;
        voltage=j*0.12207;  //(5/4096)*100      /*这个计算方法是以电源电压为基准,需要电源电压是标准5V,供电电压有波动就影响测量结果。
                                                                   如果用内部15通道做基准请参考手册文档,需要3步:1读AD口值,2读内部15通道AD值和基准数
                                                                   值,3根据公式计算*/
}
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2024-3-4 19:37:58 | 显示全部楼层
                   j = (u16)((u32)j * 119 / Bandgap);  //计算外部电压, Bandgap为1.19V, 测电压分辨率0.01V
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-5 09:30:19 | 显示全部楼层
电压值跟万用表还是接近的,就是数码管最后一位有点闪






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2024-3-5 14:24:27 | 显示全部楼层
adc_convert()有问题,j没有确定的初值,应该设置初值=0。
滤波时间太短、平均值源数据量太少,建议改为256次,这样直接取累加和高8位就是平均值。


回复 支持 反对

使用道具 举报

发表于 2024-3-5 21:54:57 | 显示全部楼层
本帖最后由 sz1988 于 2024-3-9 19:36 编辑

加大冗余度,可忽略A/D转换结果的低2位,或者更多位。
回复 支持 反对

使用道具 举报

发表于 2024-3-6 08:59:27 | 显示全部楼层
这不已经挺稳定了吗,万用表测的比你的慢多了。adc并联个小电容试试。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-6 11:07:00 | 显示全部楼层
我今天又反复试了一下,
在j这里取平均值效果不理想,
for (k=0;k<16;k++)
        j=j+get_adc12bitresult(chn);
        j=j/16;
        voltage=j*0.12207;  //(5/4096)*100
但在voltage累加再取平均值就,最后一位就不会闪了
回复 支持 反对

使用道具 举报

发表于 2024-3-7 20:12:48 来自手机浏览器 | 显示全部楼层
本帖最后由 msvcp60 于 2024-3-7 20:14 编辑

adc一般都会取采样多次,再平均
自带的adc要求不高的话还可以
回复 支持 反对

使用道具 举报

发表于 2024-3-7 21:50:21 | 显示全部楼层
我最近也在测试STC8H8K64U的ADC功能,而且为此我还新添了一块数字万用表做对比测试,建议楼主用电池给系统供电在试试看。
回复 支持 反对

使用道具 举报

发表于 2024-3-8 11:53:18 来自手机浏览器 | 显示全部楼层
hellozwt 发表于 2024-3-5 09:30
电压值跟万用表还是接近的,就是数码管最后一位有点闪

最后一位数值闪是正常的,除非基准电压一直没有一丁点波动。所以通常会在采样ad口加硬件滤波电容和进行采样值软件算法滤波
回复 支持 反对

使用道具 举报

发表于 2024-3-9 09:05:47 | 显示全部楼层

STC8H8K64U测试报告:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2024-3-15 15:46:15 | 显示全部楼层
数据要换算吧
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-7-19 10:48 , Processed in 0.327600 second(s), 12 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表