找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9368|回复: 20
打印 上一主题 下一主题
收起左侧

STC8a单片机双通道AD采集问题

  [复制链接]
跳转到指定楼层
楼主
ID:282747 发表于 2019-3-20 17:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
10黑币
单片机 stc8a8k
2路电压采集异常,求大佬指导一下程序,哪边有问题?
调试设置单通道,能采集单通道电压,设置双通道,2个都采集不了求大佬指导一下
#include"stc8f.h"#include <intrins.h>
#include <stdio.h>
#define VCC  2.50
#define uint unsigned int
#define uchar  unsigned char

#define ADC_CHANNEL0         0x00            //转换通道P1.0
#define ADC_CHANNEL1         0x01            //转换通道P1.1
#define ADC_CHANNEL2         0x02            //转换通道P1.2
#define ADC_CHANNEL3         0x03            //转换通道P1.3
#define ADC_CHANNEL4         0x04            //转换通道P1.4
#define ADC_CHANNEL5         0x05            //转换通道P1.5
#define ADC_CHANNEL6         0x06            //转换通道P1.6
#define ADC_CHANNEL7         0x07            //转换通道P1.7
#define ADC_CHANNEL8         0x08            //转换通道P0.0
#define ADC_CHANNEL9         0x09            //转换通道P0.1
#define ADC_CHANNEL10         0x0a            //转换通道P0.2
#define ADC_CHANNEL11         0x0b            //转换通道P0.3
#define ADC_CHANNEL12         0x0c            //转换通道P0.4
#define ADC_CHANNEL13         0x0d            //转换通道P0.5
#define ADC_CHANNEL14         0x0e            //转换通道P0.6

uint a;
bit flag_1= 0;bit flag_2=0;bit flag_3=0; bit flag_4=0;
uchar count=0;  // 变量计数器


void Delay500ms()                //@11.0592MHz
{
        unsigned char i, j, k;

        i = 29;
        j = 14;
        k = 54;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}


void Delay1ms(a)                //@11.0592MHz
{
        unsigned char i, j;

        i = 15;
        j = 90;
        do
        {
                while (--j);
        } while (--i);
}





void UartInit(void)                //9600bps@11.0592MHz
{
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //设定定时器1为16位自动重装方式
        TL1 = 0xE0;                //设定定时初值
        TH1 = 0xFE;                //设定定时初值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        TI=1;
}

void ADC_init()
  {
   P1M0 = 0x00;
   P1M1 = 0xff;
   P0M0 = 0x00;
   P0M1 = 0xff;
   ADCCFG = 0x0f;
   ADC_CONTR|=0x80; //开启AD转换电源
   Delay1ms(2);
  }

uint ADC_GetResult(unsigned char ch)
{
   uint ADC_Value=0;
   ADC_RES=0;
   ADC_RESL=0;
   ADC_CONTR|= ch;
   ADC_CONTR|= 0x40;//启动AD转换
   Delay1ms(1);
   while(!(ADC_CONTR&0x20));
   ADC_CONTR&=~0x20;                  //清完成标志
   ADC_Value=ADC_RES;                                                                //读取ADC高八位
  ADC_Value=(ADC_Value<<8)|ADC_RESL;//读取ADC低四位,并且数据合并
  ADC_Value>>=4;                                                                                //数据右移4位,高12位为所需要的数据
  return ADC_Value;  

  }

void Timer0Init(void)                //1毫秒@11.0592MHz
{
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        EA = 1;                        //开总中断
        ET0 = 1;           //开定时器T1中断
}

void Timer0(void) interrupt 1
  {
   TL0 = 0xCD;                //设置定时初值
   TH0 = 0xD4;                //设置定时初值
        count++;                 //每次中断加1
   if(count>=20)         //如果计数到了100ms
         {
           flag_1= 1;
         }
   if (count>=40)
     {
           flag_2= 1;
         }
   if (count>=60)
          {
           flag_3= 1;
          }
   if (count>=80)
      {
           count=0;
           flag_4= 1;
          }
   }


void main()
{
  float Vin1,Vin2;
  uint AD1=0;
  uint AD2=0;
  ADC_init();
  Timer0Init();
  UartInit();
  printf("串口初始化完毕");
  while(1)
  {
    if(flag_1==1)
          {        
           flag_1=0;
           AD1=ADC_GetResult(ADC_CHANNEL6);
                }                           
        if(flag_2==1)
          {
           flag_2=0;
         Vin1 = VCC*AD1/4090;
          }
        if(flag_3==1)
          {        
           flag_3=0;
          AD2=ADC_GetResult(ADC_CHANNEL5);
          }                           
         if(flag_4==1)
          {        
           flag_4=0;
         Vin2 = VCC*AD2/4090;
           }
        printf ("%.2f,%.2f",Vin1,Vin2);
        Delay500ms();
   }
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:491577 发表于 2019-3-20 21:18 | 只看该作者
红色部分有问题,应该用else if语句,先写:
if (count>=80)

flag_4= 1;

else if (count>=60)

flag_3= 1;

......
void Timer0(void) interrupt 1
  {
   TL0 = 0xCD;                //设置定时初值
   TH0 = 0xD4;                //设置定时初值
        count++;                 //每次中断加1
  if(count>=20)         //如果计数到了100ms
         {
           flag_1= 1;
         }
   if (count>=40)
     {
           flag_2= 1;
         }
   if (count>=60)
          {
           flag_3= 1;
          }
   if (count>=80)
      {
           count=0;
           flag_4= 1;

          }
   }
回复

使用道具 举报

板凳
ID:282747 发表于 2019-3-20 23:40 来自手机 | 只看该作者
hhh402 发表于 2019-3-20 21:18
红色部分有问题,应该用else if语句,先写:
if (count>=80)


不行啊,朋友这样改,连子程序都进不去
回复

使用道具 举报

地板
ID:282747 发表于 2019-3-21 00:10 来自手机 | 只看该作者
自己解决了,多通道采集需要把原通道清零
回复

使用道具 举报

5#
ID:401564 发表于 2019-3-21 09:57 | 只看该作者
shijie240 发表于 2019-3-21 00:10
自己解决了,多通道采集需要把原通道清零

缓存要清除而已,两个ADC结果保存的寄存器不需要清除的,一次完整的ADC运行之后,这两个寄存器自然就保存了本次ADC的结果了
回复

使用道具 举报

6#
ID:282747 发表于 2019-3-21 11:46 | 只看该作者
Y_G_G 发表于 2019-3-21 09:57
缓存要清除而已,两个ADC结果保存的寄存器不需要清除的,一次完整的ADC运行之后,这两个寄存器自然就保存了 ...

ADC_CONTR|= ch;通道选择要清除上一个选择的通道,要不然进不了下一个,多通道循环采集不了
回复

使用道具 举报

7#
ID:401564 发表于 2019-3-21 16:29 | 只看该作者
shijie240 发表于 2019-3-21 11:46
ADC_CONTR|= ch;通道选择要清除上一个选择的通道,要不然进不了下一个,多通道循环采集不了

ADC_CONTR|= ch
这个是通道选择,单片机只有一个ADC电路,但它有15个ADC的IO端口,所以,你是一定要选择哪个通道进行ADC才能正确的进行ADC,它实际上是一个类似选择开关的样子
其实我看不懂你的程序,我是用汇编的,但我感觉你的代码是有点多了,就是汇编也用不了那么多的代码量的,更何况是C呢
回复

使用道具 举报

8#
ID:282747 发表于 2019-3-25 11:42 | 只看该作者
Y_G_G 发表于 2019-3-21 16:29
ADC_CONTR|= ch
这个是通道选择,单片机只有一个ADC电路,但它有15个ADC的IO端口,所以,你是一定要选择哪个 ...

我这个是测试代码,随便编的
回复

使用道具 举报

9#
ID:394367 发表于 2019-3-29 13:45 | 只看该作者
学习了,楼主,我也正用到
回复

使用道具 举报

10#
ID:375092 发表于 2019-3-30 11:20 | 只看该作者
楼主,你不把这个写在中断里面,直接在主函数中调用一个函数直接在主函数中直接显示会比较好,我之前都有做过,最多几毫秒的延时就够了,直接改变通道就行了
回复

使用道具 举报

11#
ID:282747 发表于 2019-4-3 09:50 | 只看该作者
609763691 发表于 2019-3-30 11:20
楼主,你不把这个写在中断里面,直接在主函数中调用一个函数直接在主函数中直接显示会比较好,我之前都有做 ...

我采集的13个通道数据,必须精确的微秒,这个是我的测试程序,项目是在子程序里面的
回复

使用道具 举报

12#
ID:272876 发表于 2019-4-23 15:43 | 只看该作者
609763691 发表于 2019-3-30 11:20
楼主,你不把这个写在中断里面,直接在主函数中调用一个函数直接在主函数中直接显示会比较好,我之前都有做 ...

分下下你的程序呗大佬
回复

使用道具 举报

13#
ID:272876 发表于 2019-4-23 15:45 | 只看该作者
我想写一个7通道的  该怎么搞啊  能不能分享下你的程序
回复

使用道具 举报

14#
ID:272876 发表于 2019-4-24 15:35 | 只看该作者
shijie240 发表于 2019-3-21 00:10
自己解决了,多通道采集需要把原通道清零

怎么清零原通道 我试了下 没成功
回复

使用道具 举报

15#
ID:272876 发表于 2019-4-24 17:25 | 只看该作者
609763691 发表于 2019-3-30 11:20
楼主,你不把这个写在中断里面,直接在主函数中调用一个函数直接在主函数中直接显示会比较好,我之前都有做 ...

能分享下程序吗
回复

使用道具 举报

16#
ID:157579 发表于 2019-7-10 16:11 | 只看该作者
您好,关于STC8A单片机双通道AD采集源码,您这边能不能分享一下。
回复

使用道具 举报

17#
ID:581932 发表于 2019-7-10 21:13 | 只看该作者
楼主。怎么清零通道?我也遇到这个问题了。
我的ADC函数和你差不多的。
uint GetADCresults(uchar adcch)
{
        ADC_RES  = 0;
        ADC_RESL = 0;

        ADC_CONTR |= ADC_START|adcch;               //¿aÆôADC
        Delay(10);
        while(!(ADC_CONTR & ADC_FLAG));            
        ADC_CONTR &= ~ADC_FLAG;                  
        ADC_CONTR &= ~ADC_START;                  
       
        return (ADC_RES<<8 | ADC_RESL);
}
主函数里面调用函数,传通道值获得ADC结果,但是两个通道得到的数据是一样的。
DZ_Data = GetADCresults(ADCch_dz);
GD_Data = GetADCresults(ADCch_gd);

这两句之间做了500ms 的延时,结果取出来还是差不多的,有时候还一样。
请帮忙!~
回复

使用道具 举报

18#
ID:581305 发表于 2019-7-18 10:56 | 只看该作者
echowilson 发表于 2019-7-10 21:13
楼主。怎么清零通道?我也遇到这个问题了。
我的ADC函数和你差不多的。
uint GetADCresults(uchar adcch) ...

ADC_CONTR |= ADC_START|adcch; 这里有问题
回复

使用道具 举报

19#
ID:117310 发表于 2019-9-12 23:36 | 只看该作者
我也是做八通道顺序采集,开始没有在循环结束时候加禁用ADC指令时候,第八通道电压不对,而且零点也有十几个字,加了禁用后,零点只有一个字,但是第一个通道没有数据,始终是0,不知道怎么回事了?


        ADCCFG = 0x20; //设置ADC结果右对齐,转换速度为最快
        for (i = 0; i < 8; i++)
            {
                ADC_CONTR = (0x80 | i );                       //使能ADC模块并设置通道
                ADC_CONTR |= 0x40;                          //启动AD转换
                _nop_();
                _nop_();
                while (!(ADC_CONTR & 0x20));                //查询ADC完成标志
                ADC_CONTR &= ~0x20;                         //清完成标志
                ADC[i] = (ADC_RES << 8) | ADC_RESL;
            }
                ADC_CONTR = 0x00;//禁用ADC模块
            //8个AD结果显示输出
        for (i = 0; i < 8; i++)
            {
                UartSend(ADC[i]>>8);
                UartSend(ADC[i]);
            }            
        UartSendStr("\r\n");//输出回车换行符
回复

使用道具 举报

20#
ID:189860 发表于 2021-10-26 16:27 | 只看该作者
回复19#,你在选择通道的时候要先将ADC_CONTR &=0XF0;这样将低四位清了,再或上通道号才能真正的到你要的通道。不然一直或或的,你想想或成什么通道了?
回复

使用道具 举报

21#
ID:562627 发表于 2022-9-19 17:17 | 只看该作者
6726234500 发表于 2019-4-24 15:35
怎么清零原通道 我试了下 没成功

uint ADC_GetResult(unsigned char ch)
{
   uint ADC_Value=0;
   ADC_RES=0;
   ADC_RESL=0;
   ADC_CONTR|= ch;
   ADC_CONTR|= 0x40;//启动AD转换
   Delay1ms(1);
   while(!(ADC_CONTR&0x20));
   ADC_CONTR&=~0x20;                  //清完成标志
   ADC_Value=ADC_RES;                                                                //读取ADC高八位
  ADC_Value=(ADC_Value<<8)|ADC_RESL;//读取ADC低四位,并且数据合并
  ADC_Value>>=4;                                                                                //数据右移4位,高12位为所需要的数据
  ADC_RES=0;                           //清除ADC高8位数据
ADC_RESL=0;                           //清除ADC低4位数据
  return ADC_Value;  

  }

即转换1次清除1次数据
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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