前言

经过这么几个月的奋战,CT107D开发板上的功能基本摸索得差不多了。今天呢,搞了一下PCF8591.

芯片简介

概述

PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。

功能

PCF8591的功能包括多路模拟输入、内置跟踪保持、8-bit模数转换和8-bit数模转换。PCF8591的最大转化速率由I2C总线的最大速率决定。

原理图

1.png

引脚图

2.png

PCF8591的器件地址

Snip20200222_1.png

PCF8591的控制寄存器

Snip20200222_2.png

程序实现

现在我们已经大致了解了PCF8591这款芯片了,现在我们来看看怎么反对他操作。
由于本文章只对其做AD转换所以我们来看看AD转换的时序就行了。
Snip20200222_3.png

PCF8591读取操作

读取的第一个字节是包含上一次转换结果
将上一个字节读取时,才开始进行这次转换的采样。
读取的第二个字节才是这次的转换结果。
所以读取转换结果的步骤是:发送转换命令,将上次的结果读走,然后等一会儿,然后读取结果。

示例程序

/************************************************************
* 函数名       : Pcf8591ReadByte
* 函数功能   : 读取一个转换值
* 输入           :
* 输出           : dat
************************************************************/
unsigned char Pcf8591ReadByte()
{
    unsigned char dat;
    I2cStart();
    I2cSendByte(READADDR);//发送读器件地址
    dat=I2cReadByte();//读取数据
    I2cStop();          //结束总线
  return dat;
}

数据转换

由于我们通过芯片转换读取出来的值是0-255,并不能表示电压值。所以我们需要通过公式简单转换一下。
转换公式:电压值=读取值/255*5
通过这么一个公式所得出来的值就是实际的电压值了。
最后再配合数码管显示就可以实现输出了。

数码管经验分享

借这个机会我想做一个关于数码管的经验分享。
在我们对数码管进行动态显示的时候,需要不停的去扫描她,但是呢,在进行一些通信协议操作的时候,往往会出错。于是我们就想到了一个办法,就是在进行通信操作之前我们把定时器关掉,但是这样的话在操作通信的时候数码管会闪一下,而且很明显。
所以我想到了一个办法,把定时一次扫描8次变成扫描一次,也就是说定时一次我们就显示一位,这样在进行通信的时候关掉定时器基本看不到什么闪烁。

完整程序

最后我贴上我写的完整程序

#include <reg52.h>
#include <absacc.h>
#include <IIC.h>

#define uint unsigned int
#define uchar unsigned char

//共阳数码管数码管段码
uchar code duan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
//数码管位码
uchar code wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//8位数码管缓存区
uchar smg_count[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

//延迟1ms程序
void Delay1ms(uint timee)        //@12.000MHz
{
    unsigned char i, j;
    while(timee --)
    {
        i = 12;
        j = 169;
        do
        {
            while (--j);
        } while (--i);
    }
}

//操作138译码器传输数据
//w:第几个寄存器
//dat:所需要传输的数据
void HC_138(uchar w,dat)
{
    switch(w)
    {
        case 0:P2 &= 0x1f;break;
        case 1:P2 = (P2 &= 0x1f) | 0x20;break;
        case 2:P2 = (P2 &= 0x1f) | 0x40;break;
        case 3:P2 = (P2 &= 0x1f) | 0x60;break;
        case 4:P2 = (P2 &= 0x1f) | 0x80;break;
        case 5:P2 = (P2 &= 0x1f) | 0xa0;break;
        case 6:P2 = (P2 &= 0x1f) | 0xc0;break;
        case 7:P2 = (P2 &= 0x1f) | 0xe0;break;
    }
    P0 = dat;
}

//数码管显示子程序
void smg_display()
{
        uchar i;
        //给数码管送入位码数据
        HC_138(6,wei[i]);
        //给数码管送入段码数据
        HC_138(7,*(smg_count + i));
        Delay1ms(2);
        if(++i == 8)
        {
            i = 0;
        }
}

void Timer0Init(void)        //定时器0初始化@12.000MHz
{
    AUXR |= 0x80;        //选择1T模式
    TMOD &= 0xF0;        //模式选择
    TL0 = 0x20;        //送入初值
    TH0 = 0xD1;        //送入初值
    TF0 = 0;        //清空标志位
    TR0 = 1;        //打开定时器
    EA = 1;         //打开总中断
    ET0 = 1;        //打开定时器0中断
}

//adc转换标志位
bit adc_flag = 0;
//主程序
void main()
{
    uchar team;     //暂存读取数据
    int team1;
    int team2;
    HC_138(4,0xff);    //关LED灯
    HC_138(5,0x00);    //关蜂鸣器、继电器
    Timer0Init();      //定时器0初始化
    init_adc();        //PCF8592初始化
    while(1)
    {
        if(adc_flag)
        {
            adc_flag = 0;     //转换标志位清零
            TR0 = 0;          //关闭定时器,防止通信协议出错
            team = Read_adc();  //开始读取所转换的值
            TR0 = 1;          //打开定时器

            //电压转换公式:电压值=读取值/255*5 这里是保留小数后面两位;
            team1 = team * 5 / 255 *100;    
            //分别把值赋给数码管
            smg_count[5] = duan[(team1/100)] & 0x7f;   
            smg_count[6] = duan[team1%100/10];
            smg_count[7] = duan[team%10];
        }
    }
}

//定时器0服务函数
void timer0() interrupt 1
{
    //静态变量,用于存放定时次数
    static uchar flag = 0;
    flag ++;

    //如果到了50ms则启动转换
    if(flag == 50)
    {
        adc_flag = 1;
        flag = 0;
    }
    //数码管显示函数
    smg_display();
}

本次文章就写到这里啦!感谢观看哦!!!

Last modification:February 22nd, 2020 at 06:11 pm
如果觉得我的文章对你有用,请随意赞赏