找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4622|回复: 15
收起左侧

使用STC15W408AS单片机自带的AD转换中遇到的问题,虚心求教

[复制链接]
ID:601478 发表于 2019-10-14 09:17 | 显示全部楼层 |阅读模式
说明:下面的程序是一个测温程序,用的STC15W408AS自带的AD转换通道,P1.2 I/O口输入被测变化电平,使用的NTC负温度系数传感器,现在遇到的问题是把程序烧录进硬件,上电后在4段数码管上显示的转换后的温度值在人为加热传感器 的情况下数值只在上电后3到4秒内会发生变化,时间一长再怎么加热数值也不会变了,传感器温度都7.80度了显示的数值也是一开始的32度,没变化,但是掉电后重新上电又有几秒钟可以正常显示60多度的温度值,之后又卡在那里怎样加温降温显示值也不变,感觉就是只有硬件上电初时的几秒会工作,之后就莫名卡死跑飞,很是奇怪,程序自己看了好多遍感觉看不出什么问题,小弟刚接触单片机,也不知道哪里写的不对,求各路大佬好心指点一下,感激不尽

上程序:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int


typedef unsigned char BYTE;
typedef unsigned int WORD;

......
......
#define ADC_POWER 0x80
#define ADC_FLAG 0x10
#define ADC_START 0x08
#define ADC_SPEED 0x00

sbit STB = P3^3;
sbit CLK = P3^6;
sbit DIO = P3^7;
sbit KEY = P1^5;


uchar code zhuzhi[101] ={65,62, 59,...........3,2,1};//温度对应的阻值表

void delay(uchar a)  // 延时
{
        uchar x;
        while(a--)
        {
                x = 200;
                while(x--);
        }
}


void init_ADC()  //初始化AD
{
        P1ASF = 0x06;
  delay(20);
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = ADC_POWER | ADC_SPEED;
}


WORD res_ADC(BYTE ch) //启动转换
{
        uint num;
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = ADC_POWER | ADC_SPEED | ADC_START | ch;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        while(!(ADC_CONTR & ADC_FLAG));
        ADC_CONTR &= ~ADC_FLAG;
        num = (ADC_RES<<2)|ADC_RESL;
        return num;
}


float are()  // 多次取值后求平均,再用公式转成电阻值
{
        uchar i,u;
        uint a,b;
        float n;
        u = ch();
        for(i = 0;i<31;i++)
        {
                a = res_ADC(u);
                b += a;
        }
        b = b/31;
        n = b*0.1/(5.5-0.005*b);
        
        return n;
}

float are2()  //滤波
{
        uchar i;
        float l,k;
        for(i = 0;i<30;i++)
        {
                l = are();
                k += l;
        }
        k = k/30;
        return k;
}


void ADC_biao()  //查表找对应的温度数值
{
        float r;
        uchar high,low,mid;
        low = 0;
        high = 100;
        mid = (low + high)/2;
        r = are2();
        if((zhuzhi[high]<=r) && (r<=zhuzhi[low]))
        {
                while((high - low) != 1)
                {
                        if(r<zhuzhi[mid])
                        {
                                low = mid+1;
                                mid = (low + high)/2;
                        }
                        else if(zhuzhi[mid]<r)
                        {
                                high = mid-1;
                                mid = (low+high)/2;
                        }
                        else
                        {
                                display(mid);
                        }
                }
                if((zhuzhi[low] - r) < (r - zhuzhi[high]))
                {
                        display(low);
                }
                else if((r - zhuzhi[high]) < (zhuzhi[low] - r))
                {
                        display(high);
                }
                else
                {
                        display(high);
                }
        }
        else
        {
                if(r<zhuzhi[high])
                {
                        display(high);
                }
                if(zhuzhi[low]<r)
                {
                        display(low);
                }
        }
}

void main()  //主循环
{
        P1M1 = 0;
        P1M0 = 0;
        KEY = 1;
        init_ADC();
        while(1)
        {
                ADC_biao();
                delay(25);
        }
}


回复

使用道具 举报

ID:213173 发表于 2019-10-14 11:11 | 显示全部楼层
你确认这个程序能通过编译?硬件电路是什么样的?
回复

使用道具 举报

ID:601478 发表于 2019-10-14 13:30 | 显示全部楼层
wulin 发表于 2019-10-14 11:11
你确认这个程序能通过编译?硬件电路是什么样的?

能通过编译,硬件电路用的开发板,具体我也不太懂
回复

使用道具 举报

ID:213173 发表于 2019-10-14 15:24 | 显示全部楼层
PDDDF 发表于 2019-10-14 13:30
能通过编译,硬件电路用的开发板,具体我也不太懂

我可以负责任的对你说,你发的这个程序根本就不完整,不可能通过编译。使用STC15W408AS芯片可以用51头文件,但必须声明51头文件中不包含的特殊寄存器的地址。如:
sfr ADC_CONTR   =   0xBC;           //ADC控制寄存器
sfr ADC_RES     =   0xBD;           //ADC高8位结果
sfr ADC_LOW2    =   0xBE;           //ADC低2位结果
sfr P1ASF       =   0x9D;           //P1口第2功能控制寄存器
sfr P1M0        =   0x92;   /端口1模式寄存器0
sfr P1M1        =   0x91;   /端口1模式寄存器1
ADC转换结果是12位,你的温度对应的阻值表是8位数组,并且数组成员不完整。
你的数码管显示函数在哪里?
P1M1 = 0;P1M0 = 0;表示P1口全部是弱上拉准双向口,应该把ADC输入设为高阻口,如果是用P1.0口作ADC输入应设为P1M1 = 0x01;P1M0 = 0x00;
设置P1的第0通道端口作为模拟输入P1ASF=0x01;

回复

使用道具 举报

ID:47286 发表于 2019-10-14 20:46 | 显示全部楼层
用P1M0和P1M1把P1.2端口置成高阻状态

然后 在AD的采集端 用万用表测量电压 如果电压持续随温度变化则检查端口配置和程序 否则检查硬件
回复

使用道具 举报

ID:401564 发表于 2019-10-15 11:58 | 显示全部楼层
我用的时汇编的,看不明白你这明白
但编程的原理是一样的,你一下子搞那么多代码放这,哪里出了问题都可能找不到
你可以先写一个单独的ADC程序,也不用查表显示什么的,不用滤波处理
简单的:一直进行ADC再把结果输出到一个带LED的端口就可以了,要保证用手摸一下NTC,端口的LED就跟着变化就可以,用来验证ADC代码是否正确,其它功能也是这样一步一步的来就可以了
汇编的思维就是这样的,保证一个一个小功能正确了再去搞别的功能
顺便说一下,取平均值那一段,尽可能的用整形,不要用浮点型,能用位移就不要用除法运算,在C上面它是可以正确计算的,但编译器编译之后就不一定是正确的算法了,你可以对比一下官方的手册,它取平均值也是用位移的方法来计算的
回复

使用道具 举报

ID:601478 发表于 2019-10-16 09:47 | 显示全部楼层
Y_G_G 发表于 2019-10-15 11:58
我用的时汇编的,看不明白你这明白
但编程的原理是一样的,你一下子搞那么多代码放这,哪里出了问题都可能找 ...

我现在就是试着实现这块芯片的AD转换功能,程序的思路就是简单的一直循环检测输入电平和显示温度值,取平均值那里我也换成整形变量了,移位求商这个真的头一次知道,现在细节还在弄,谢谢大佬的回复
回复

使用道具 举报

ID:601478 发表于 2019-10-16 10:13 | 显示全部楼层
wulin 发表于 2019-10-14 15:24
我可以负责任的对你说,你发的这个程序根本就不完整,不可能通过编译。使用STC15W408AS芯片可以用51头文 ...

来了个大佬666
是这样的程序的确不是完整的,我上面只发了有关AD转换的部分,数码管显示部分我想着关系不大就省略没发出来,那个阻值表是我用的NTC热敏电阻的温度—阻值对应表,1到100度对应的阻值,是问厂家那里拿的;p1口的状态我改了高阻态但是还是不行;还有测温的电路图我不太会分析,AD转换得到的Vout和Rt热敏间的关系怎样求,能麻烦大佬帮忙看下吗,谢谢大佬回复
完整程序:
#include<reg51.h>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int

typedef unsigned char BYTE;
typedef unsigned int WORD;


#define FOSC    11059200L

sfr P1M1 = 0x91;
sfr P1M0 = 0x92;

sfr ADC_CONTR = 0xBC;
sfr ADC_RES = 0xBD;
sfr ADC_RESL = 0xBE;
sfr P1ASF = 0x9D;
sfr CLK_DIV = 0x97;

sbit STB = P3^3;
sbit CLK = P3^6;
sbit DIO = P3^7;
sbit KEY = P1^5;

#define ADC_POWER   0x80
#define ADC_FLAG    0x10
#define ADC_START   0x08
#define ADC_SPEED   0x60

WORD num;
float n;
uchar u = 1;

void display(uchar K);
void delay(WORD n);
uchar code Duanma[10]={0xfa,0x82,0xb9,0xab,0xc3,0x6b,0x7b,0xa2,0xfb,0xe3};
uchar code zhuzhi[101]={65.83,62.54,59.43,56.49,53.72,51.10,48.62,46.28,
                              44.06,41.96,39.97,38.09,36.31,34.63,33.03,31.51,
                              30.07,28.71,27.41,26.18,25.02,23.91,22.86,21.86,
                              20.90,20.00,19.14,18.32,17.54,16.80,16.10,15.42,
                              14.78,14.17,13.59,13.04,12.51,12.00,11.52,11.06,
                              10.62,10.20,9.80,9.42,9.05,8.70,8.37,8.05,7.74,
                              7.45,7.17,6.90,6.65,6.40,6.17,5.94,5.73,5.52,5.32,5.13,
                        4.95,4.77,4.61,4.45,4.29,4.14,4.00,3.86,3.73,3.61,
                        3.48,3.37,3.25,3.15,3.04,2.94,2.85,2.75,2.67,2.58,
                        2.50,2.42,2.34,2.27,2.20,2.13,2.06,2.00,1.94,1.88,
                        1.82,1.77,1.71,1.66,1.61,1.56,1.52,1.47,1.43,1.39,
                        1.35};

void send_8bit(uchar dat)
{
        uchar i;
        for(i=0;i<8;i++)
        {
                if(dat&0x01)
                {
                        DIO = 1;
                }
                else
                {
                        DIO = 0;
                }
               
                CLK = 0;
                CLK = 1;
               
                dat=dat>>1;
        }
}

void command(uchar com)
{
        STB = 1;
        STB = 0;
        send_8bit(com);
}

void display(uchar K)
{
         uchar ge,shi,bai;
   ge = K%10;
         shi = (K/10)%10;
         bai = (K/100)%10;
       
         command(0x03);
         command(0x40);
         command(0xc6);
       
        send_8bit(Duanma[bai]);              
        send_8bit(0x00);

        send_8bit(0x00);            
        send_8bit(0x00);

  send_8bit(Duanma[shi]);
        send_8bit(0x00);

        send_8bit(Duanma[ge]);
        send_8bit(0x00);

        command(0x8f);
        STB = 1;
}

void init_ADC()
{
        P1ASF = 0x06;
        delay(2);
        ADC_RES = 0;
        ADC_RESL = 0;
}

void resetADC(BYTE ch)
{
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = ADC_SPEED | ADC_START | ADC_POWER | ch;
}

void delay(WORD n)
{
        uint x;
        while(n--)
        {
                x = 500;
                while(x--);
        }
}

void get_result()
{
  while (!(ADC_CONTR & ADC_FLAG));
        ADC_CONTR &= ~ADC_FLAG;
  num = (ADC_RES<<2)|ADC_RESL;
}

WORD lvbo()
{
        WORD count;
        uchar i = 0;
        for(i = 0;i<32;i++)
        {
          resetADC(u);
    delay(2);
          get_result();
                count += num;
        }
        count = count>>5;
        return count;
}

void chselect()
{
        if(KEY == 0)
        {
                delay(5);
                if(KEY == 0)
                {
                        while(KEY == 0);
      if(2<++u) u = 1;
                }
        }
}

void data_change()
{
        WORD i;
        i = lvbo();
  n = i/(55-0.05*i);
}

void cha_biao()
{
        uint low,high,middle;
        low = 0;
        high = 100;
        middle = (high + low)/2;
        if((n<=zhuzhi[low])&&(zhuzhi[high]<=n))
        {
           while((high - low) != 1)
           {
                   if(n < zhuzhi[middle])
                   {
                           low = middle+1;
                                 middle = (high + low)/2;
                         }
                         else if(zhuzhi[middle] < n)
                   {
                                 high = middle-1;
                                 middle = (high + low)/2;
                   }
                         else
                         {
                                 if(n == zhuzhi[middle])
                                 {
                                         display(middle);
                                         return;
                                 }
                         }
                 }
                 if((zhuzhi[low]-n)<(n-zhuzhi[high]))
                 {
                         display(low);
                         return;
                 }
                 if((n-zhuzhi[high])<(zhuzhi[low]-n))
                 {
                         display(high);
                         return;
                 }
         }
        else
        {
                if(n<zhuzhi[high])
                {
                        display(high);
                        return;
                }
                if(zhuzhi[low]<n)
                {
                        display(low);
                        return;
                }
        }
}

void main()
{
        P1M1 = 0x06;
        P1M0 = 0x00;
        KEY = 1;
       
        init_ADC();
        while(1)
        {
                chselect();
    lvbo();
                resetADC(u);
    delay(2);
          get_result();
                data_change();
                cha_biao();
                delay(6);
        }
}C:\Users\Administrator\Desktop\01
回复

使用道具 举报

ID:601478 发表于 2019-10-16 10:19 | 显示全部楼层
dzbj 发表于 2019-10-14 20:46
用P1M0和P1M1把P1.2端口置成高阻状态

然后 在AD的采集端 用万用表测量电压 如果电压持续随温度变化则检 ...

硬件应该不会有问题吧,开发板买了才不到两个月,我还是怀疑自己的程序问题(其实在考虑要不要买个万用表),但是又看不出是哪里出错,哎,难搞
回复

使用道具 举报

ID:213173 发表于 2019-10-16 13:13 | 显示全部楼层
PDDDF 发表于 2019-10-16 10:13
来了个大佬666
是这样的程序的确不是完整的,我上面只发了有关AD转换的部分,数码管显示部分我想 ...

软件都是基于硬件条件编写的,把你的开发板原理图或实物照片发上来,帮你改程序。NTC热敏电阻的温阻表不可以直接使用,要根据分压电阻值计算出温度电压关系制作数组表格。不要追求一步完成完美的代码,应该循序渐进,先完成基本的AD转换,逐渐学习滤波、换算等功能。
回复

使用道具 举报

ID:10947 发表于 2019-10-16 14:27 | 显示全部楼层
最简单的,你得保证P1.2脚的电压是对的,在显示不正常的时候,有测量过P1.2的电压吗
回复

使用道具 举报

ID:601478 发表于 2019-10-19 13:48 | 显示全部楼层
wulin 发表于 2019-10-16 13:13
软件都是基于硬件条件编写的,把你的开发板原理图或实物照片发上来,帮你改程序。NTC热敏电阻的温阻表不 ...

方便加个QQ交流学习一下吗,我上个回复的图片发不出来,可以的话QQ截图比较快
回复

使用道具 举报

ID:601478 发表于 2019-10-19 13:56 | 显示全部楼层
lfc315 发表于 2019-10-16 14:27
最简单的,你得保证P1.2脚的电压是对的,在显示不正常的时候,有测量过P1.2的电压吗

万用表刚到手,我测测看
回复

使用道具 举报

ID:491577 发表于 2019-10-20 00:58 | 显示全部楼层
WORD res_ADC(BYTE ch) //启动转换
{
        uint num;
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = ADC_POWER | ADC_SPEED | ADC_START | ch;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        while(!(ADC_CONTR & ADC_FLAG));
        ADC_CONTR &= ~ADC_FLAG;
        num = (ADC_RES<<2)|ADC_RESL;
        return num;
}
这个函数中:num = (ADC_RES<<2)|ADC_RESL;这个不对,数据溢出了。改成:num = ((uint)ADC_RES<<2)|ADC_RESL;或者num = (uint)ADC_RES*4+ADC_RESL;
回复

使用道具 举报

ID:601478 发表于 2019-10-21 14:30 | 显示全部楼层
hhh402 发表于 2019-10-20 00:58
WORD res_ADC(BYTE ch) //启动转换
{
        uint num;

是数据溢出,不过不是这里,是另外的滤波函数,谢谢你给我的提示,问题解决了
回复

使用道具 举报

ID:601478 发表于 2019-10-21 14:32 | 显示全部楼层
原因找到了,滤波时数据溢出,换了变量类型就没事了,谢谢楼上几位老哥的回复,先结贴了
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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