国产成人av人人爽人人澡-亚洲国产日韩欧美一区-好吊日视频这里只有精品-日本高清精品视频在线

你好!歡迎來到深圳市穎特新科技有限公司!
語言
當(dāng)前位置:首頁 >> 技術(shù)中心 >> 單片機入門 >> PCF8591的軟件編程

PCF8591的軟件編程

作者:admin 來源:不詳 發(fā)布時間:2018-05-08  瀏覽:10

  PCF8591的通信接口是I2C,那么編程肯定是符合這個協(xié)議的。單片機對PCF8591進行初始化,一共發(fā)送三個字節(jié)即可。第一個字節(jié),和EEPROM類似,第一個字節(jié)是地址字節(jié),其中7位代表地址,1位代表讀寫方向。地址高4位固定是1001,低三位是A2,A1,A0,這三位我們電路上都接了GND,因此也就是000,如圖1所示。

PCF8591地址字節(jié)

圖1 PCF8591地址字節(jié)

   發(fā)送到PCF8591的第二個字節(jié)將被存儲在控制寄存器,用于控制PCF8591的功能。其中第3位和第7位是固定的0,另外6位各自有各自的作用,如圖2所示,我逐一介紹。

 圖17-6 PCF8591控制字節(jié)

圖2 PCF8591控制字節(jié)

  控制字節(jié)的第6位是DA使能位,這一位置1表示DA輸出引腳使能,會產(chǎn)生模擬電壓輸出功能。第4位和第5位可以實現(xiàn)把PCF8591的4路模擬輸入配置成單端模式和差分模式,單端模式和差分模式的區(qū)別,我們17.4章節(jié)有介紹,這里大家只需要知道這兩位是配置AD輸入方式的控制位即可,如圖3所示。

PCF8591模擬輸入配置方式

圖3 PCF8591模擬輸入配置方式

   控制字節(jié)的第2位是自動增量控制位,自動增量的意思就是,比如我們一共有4個通道,當(dāng)我們?nèi)渴褂玫臅r候,讀完了通道0,下一次再讀,會自動進入通道1進行讀取,不需要我們指定下一個通道,由于A/D每次讀到的數(shù)據(jù),都是上一次的轉(zhuǎn)換結(jié)果,所以同學(xué)們在使用自動增量功能的時候,要特別注意,當(dāng)前讀到的是上一個通道的值。為了保持程序的通用性,我們的代碼沒有使用這個功能,直接做了一個通用的程序。

  控制字節(jié)的第0位和第1位就是通道選擇位了,00、01、10、11代表了從0到3的一共4個通道選擇。

  發(fā)送給PCF8591的第三個字節(jié)D/A數(shù)據(jù)寄存器,表示D/A模擬輸出的電壓值。D/A模擬我們一會介紹,大家知道這個字節(jié)的作用即可。我們?nèi)绻麅H僅使用A/D功能的話,就可以不發(fā)送第三個字節(jié)。

  下面我們用一個程序,把AIN0、AIN1、AIN3測到的電壓值顯示在液晶上,同時大家可以轉(zhuǎn)動電位器,會發(fā)現(xiàn)AIN0的值發(fā)生變化。

/***********************lcd1602.c文件程序源代碼*************************/

#include <reg52.h>

 

#define LCD1602_DB   P0

 

sbit LCD1602_RS = P1^0;

sbit LCD1602_RW = P1^1;

sbit LCD1602_E  = P1^5;

 

void LcdWaitReady()  //等待液晶準備好

{

    unsigned char sta;

    

    LCD1602_DB = 0xFF;

    LCD1602_RS = 0;

    LCD1602_RW = 1;

    do

    {

        LCD1602_E = 1;

        sta = LCD1602_DB; //讀取狀態(tài)字

        LCD1602_E = 0;

    } while (sta & 0x80); //bit7等于1表示液晶正忙,重復(fù)檢測直到其等于0為止

}

void LcdWriteCmd(unsigned char cmd)  //寫入命令函數(shù)

{

    LcdWaitReady();

    LCD1602_RS = 0;

    LCD1602_RW = 0;

    LCD1602_DB = cmd;

    LCD1602_E  = 1;

    LCD1602_E  = 0;

}

void LcdWriteDat(unsigned char dat)  //寫入數(shù)據(jù)函數(shù)

{

    LcdWaitReady();

    LCD1602_RS = 1;

    LCD1602_RW = 0;

    LCD1602_DB = dat;

    LCD1602_E  = 1;

    LCD1602_E  = 0;

}

void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str)  //顯示字符串,屏幕起始坐標(x,y),字符串指針str

{

    unsigned char addr;

    

    //由輸入的顯示坐標計算顯示RAM的地址

    if (y == 0)

        addr = 0x00 + x; //第一行字符地址從0x00起始

    else

        addr = 0x40 + x; //第二行字符地址從0x40起始

    

    //由起始顯示RAM地址連續(xù)寫入字符串

    LcdWriteCmd(addr | 0x80); //寫入起始地址

    while (*str != '\0')      //連續(xù)寫入字符串?dāng)?shù)據(jù),直到檢測到結(jié)束符

    {

        LcdWriteDat(*str);

        str++;

    }

}

void LcdInit()  //液晶初始化函數(shù)

{

    LcdWriteCmd(0x38);  //16*2顯示,5*7點陣,8位數(shù)據(jù)接口

    LcdWriteCmd(0x0C);  //顯示器開,光標關(guān)閉

    LcdWriteCmd(0x06);  //文字不動,地址自動+1

    LcdWriteCmd(0x01);  //清屏

}

/***********************I2C.c文件程序源代碼*************************/

#include <reg52.h>

#include <intrins.h>

 

#define I2CDelay()  {_nop_();_nop_();_nop_();_nop_();}

 

sbit I2C_SCL = P3^7;

sbit I2C_SDA = P3^6;

 

void I2CStart()  //產(chǎn)生總線起始信號

{

    I2C_SDA = 1; //首先確保SDA、SCL都是高電平

    I2C_SCL = 1;

    I2CDelay();

    I2C_SDA = 0; //先拉低SDA

    I2CDelay();

    I2C_SCL = 0; //再拉低SCL

}

void I2CStop()   //產(chǎn)生總線停止信號

{

    I2C_SCL = 0; //首先確保SDA、SCL都是低電平

    I2C_SDA = 0;

    I2CDelay();

    I2C_SCL = 1; //先拉高SCL

    I2CDelay();

    I2C_SDA = 1; //再拉高SDA

    I2CDelay();

}

bit I2CWrite(unsigned char dat) //I2C總線寫操作,待寫入字節(jié)dat,返回值為應(yīng)答狀態(tài)

{

    bit ack;  //用于暫存應(yīng)答位的值

    unsigned char mask;  //用于探測字節(jié)內(nèi)某一位值的掩碼變量

 

    for (mask=0x80; mask!=0; mask>>=1) //從高位到低位依次進行

    {

        if ((mask&dat) == 0)  //該位的值輸出到SDA上

            I2C_SDA = 0;

        else

            I2C_SDA = 1;

        I2CDelay();

        I2C_SCL = 1;          //拉高SCL

        I2CDelay();

        I2C_SCL = 0;          //再拉低SCL,完成一個位周期

    }

    I2C_SDA = 1;   //8位數(shù)據(jù)發(fā)送完后,主機釋放SDA,以檢測從機應(yīng)答

    I2CDelay();

    I2C_SCL = 1;   //拉高SCL

    ack = I2C_SDA; //讀取此時的SDA值,即為從機的應(yīng)答值

    I2CDelay();

    I2C_SCL = 0;   //再拉低SCL完成應(yīng)答位,并保持住總線

 

    return (~ack); //應(yīng)答值取反以符合通常的邏輯:0=不存在或忙或?qū)懭胧。?=存在且空閑或?qū)懭氤晒?/P>

}

unsigned char I2CReadNAK() //I2C總線讀操作,并發(fā)送非應(yīng)答信號,返回值為讀到的字節(jié)

{

    unsigned char mask;

    unsigned char dat;

 

    I2C_SDA = 1;  //首先確保主機釋放SDA

    for (mask=0x80; mask!=0; mask>>=1) //從高位到低位依次進行

    {

        I2CDelay();

        I2C_SCL = 1;      //拉高SCL

        if(I2C_SDA == 0)  //讀取SDA的值

            dat &= ~mask; //為0時,dat中對應(yīng)位清零

        else

            dat |= mask;  //為1時,dat中對應(yīng)位置1

        I2CDelay();

        I2C_SCL = 0;      //再拉低SCL,以使從機發(fā)送出下一位

    }

    I2C_SDA = 1;   //8位數(shù)據(jù)發(fā)送完后,拉高SDA,發(fā)送非應(yīng)答信號

    I2CDelay();

    I2C_SCL = 1;   //拉高SCL

    I2CDelay();

    I2C_SCL = 0;   //再拉低SCL完成非應(yīng)答位,并保持住總線

 

    return dat;

}

unsigned char I2CReadACK() //I2C總線讀操作,并發(fā)送應(yīng)答信號,返回值為讀到的字節(jié)

{

    unsigned char mask;

    unsigned char dat;

 

    I2C_SDA = 1;  //首先確保主機釋放SDA

    for (mask=0x80; mask!=0; mask>>=1) //從高位到低位依次進行

    {

        I2CDelay();

        I2C_SCL = 1;      //拉高SCL

        if(I2C_SDA == 0)  //讀取SDA的值

            dat &= ~mask; //為0時,dat中對應(yīng)位清零

        else

            dat |= mask;  //為1時,dat中對應(yīng)位置1

        I2CDelay();

        I2C_SCL = 0;      //再拉低SCL,以使從機發(fā)送出下一位

    }

    I2C_SDA = 0;   //8位數(shù)據(jù)發(fā)送完后,拉低SDA,發(fā)送應(yīng)答信號

    I2CDelay();

    I2C_SCL = 1;   //拉高SCL

    I2CDelay();

    I2C_SCL = 0;   //再拉低SCL完成應(yīng)答位,并保持住總線

 

    return dat;

}

/***********************main.c文件程序源代碼*************************/

#include <reg52.h>

 

bit flag300ms = 1;       //300ms定時標志

unsigned char T0RH = 0;  //T0重載值的高字節(jié)

unsigned char T0RL = 0;  //T0重載值的低字節(jié)

 

unsigned char GetADCValue(unsigned char chn);

void ValueToString(unsigned char *str, unsigned char val);

void ConfigTimer0(unsigned int ms);

extern void LcdInit();

extern void LcdShowStr(unsigned char x, unsigned char y, const unsigned char *str);

extern void I2CStart();

extern void I2CStop();

extern unsigned char I2CReadACK();

extern unsigned char I2CReadNAK();

extern bit I2CWrite(unsigned char dat);

 

void main ()

{

    unsigned char val;

    unsigned char str[10];

    

    EA = 1;           //開總中斷

    ConfigTimer0(10); //配置T0定時10ms

    LcdInit();        //初始化液晶    

    LcdShowStr(0, 0, "AIN0  AIN1  AIN3");  //顯示通道指示

    

    while(1)

    {

        if (flag300ms)

        {

            flag300ms = 0;

            //顯示通道0的電壓

            val = GetADCValue(0);     //獲取ADC通道0的轉(zhuǎn)換值

            ValueToString(str, val);  //轉(zhuǎn)為字符串格式的電壓值

            LcdShowStr(0, 1, str);    //顯示到液晶上

            //顯示通道1的電壓

            val = GetADCValue(1);

            ValueToString(str, val);

            LcdShowStr(6, 1, str);

            //顯示通道3的電壓

            val = GetADCValue(3);

            ValueToString(str, val);

            LcdShowStr(12, 1, str);

        }

    }

}

 

unsigned char GetADCValue(unsigned char chn)  //讀取當(dāng)前的ADC轉(zhuǎn)換值,chn為ADC通道號0-3

{

    unsigned char val;

    

    I2CStart();

     if (!I2CWrite(0x48<<1))   //尋址PCF8591,如未應(yīng)答,則停止操作并返回0

    {

        I2CStop();

         return 0;

     }

    I2CWrite(0x40|chn);       //寫入控制字節(jié),選擇轉(zhuǎn)換通道

    I2CStart();

    I2CWrite((0x48<<1)|0x01); //尋址PCF8591,指定后續(xù)為讀操作    

     I2CReadACK();             //先空讀一個字節(jié),提供采樣轉(zhuǎn)換時間

     val = I2CReadNAK();       //讀取剛剛轉(zhuǎn)換完的值

     I2CStop();

    

    return val;

}

void ValueToString(unsigned char *str, unsigned char val)  //ADC轉(zhuǎn)換值轉(zhuǎn)為實際電壓值的字符串形式

{

    val = (val*25) / 255;    //電壓值=轉(zhuǎn)換結(jié)果*2.5V/255,式中的25隱含了一位十進制小數(shù)

    str[0] = (val/10) + '0'; //整數(shù)位字符

    str[1] = '.';            //小數(shù)點

    str[2] = (val%10) + '0'; //小數(shù)位字符

    str[3] = 'V';            //電壓單位

    str[4] = '\0';           //結(jié)束符

}

 

void ConfigTimer0(unsigned int ms)  //T0配置函數(shù)

{

    unsigned long tmp;

    

    tmp = 11059200 / 12;      //定時器計數(shù)頻率

    tmp = (tmp * ms) / 1000;  //計算所需的計數(shù)值

    tmp = 65536 - tmp;        //計算定時器重載值

    tmp = tmp + 12;           //修正中斷響應(yīng)延時造成的誤差

    

    T0RH = (unsigned char)(tmp >> 8);  //定時器重載值拆分為高低字節(jié)

    T0RL = (unsigned char)tmp;

    TMOD &= 0xF0;   //清零T0的控制位

    TMOD |= 0x01;   //配置T0為模式1

    TH0 = T0RH;     //加載T0重載值

    TL0 = T0RL;

    ET0 = 1;        //使能T0中斷

    TR0 = 1;        //啟動T0

}

void InterruptTimer0() interrupt 1  //T0中斷服務(wù)函數(shù)

{

    static unsigned char tmr300ms = 0;

    

    TH0 = T0RH;  //定時器重新加載重載值

    TL0 = T0RL;

    tmr300ms++;

    if (tmr300ms >= 30)  //定時300ms

    {

        tmr300ms = 0;

        flag300ms = 1;

    }

}

   細心閱讀程序的同學(xué)會發(fā)現(xiàn),我們程序在進行A/D讀取數(shù)據(jù)的時候,共使用了兩條程序去讀了2個字節(jié)。I2CReadACK(); val = I2CReadNAK();PCF8591的轉(zhuǎn)換時鐘是I2C的SCL,而A/D的特點是每次讀到的都是上一次的轉(zhuǎn)換結(jié)果,因此我們這里第一條語句的作用是產(chǎn)生一個整體的SCL時鐘提供給PCF8591進行A/D轉(zhuǎn)換,第二次是讀取當(dāng)前的轉(zhuǎn)換結(jié)果。如果我們只使用第二條語句的話,每次讀到的都是上一次的轉(zhuǎn)換結(jié)果。

編輯:admin  最后修改時間:2018-05-08

聯(lián)系方式

0755-82591179

傳真:0755-82591176

郵箱:vicky@yingtexin.net

地址:深圳市龍華區(qū)民治街道民治大道973萬眾潤豐創(chuàng)業(yè)園A棟2樓A08

Copyright © 2014-2023 穎特新科技有限公司 All Rights Reserved.  粵ICP備14043402號-4

国产超碰在线观看免费| 精品国产丝袜一区二区| 91日韩欧美国产视频| 最新日韩精品一推荐日韩精品| 欧美黄色成人真人视频| 欧美胖熟妇一区二区三区| 又色又爽又无遮挡的视频| 亚洲综合精品天堂夜夜| 久久99青青精品免费观看| 国产麻豆精品福利在线| 99精品国产自在现线观看| 精品丝袜一区二区三区性色| 观看日韩精品在线视频| 国产一区日韩二区欧美| 亚洲国产精品久久综合网| 国产在线日韩精品欧美| 五月婷婷亚洲综合一区| 亚洲熟女诱惑一区二区| 午夜福利精品视频视频| 日韩特级黄片免费在线观看| 日本东京热加勒比一区二区 | 欧美成人免费夜夜黄啪啪| 日韩中文字幕狠狠人妻| 91精品国产综合久久不卡| 99久久精品一区二区国产| 欧美二区视频在线观看| 欧美一级不卡视频在线观看| 久久99热成人网不卡| 国产主播精品福利午夜二区| 日本黄色录像韩国黄色录像| 99久久精品免费看国产高清| 日韩欧美一区二区亚洲| 国产一级二级三级观看| 欧美日韩一级黄片免费观看| 大香蕉大香蕉手机在线视频| 精品亚洲香蕉久久综合网| 日韩精品一区二区一牛| 日本加勒比在线观看一区| 国产欧美日韩精品自拍| 初尝人妻少妇中文字幕在线| 亚洲国产成人精品一区刚刚|