找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2359|回復(fù): 10
收起左側(cè)

用STC單片機(jī)和PCF8591進(jìn)行數(shù)模轉(zhuǎn)換數(shù)據(jù)并用LCD顯示時(shí)遇到的問題

[復(fù)制鏈接]
ID:508775 發(fā)表于 2019-4-17 09:02 | 顯示全部樓層 |閱讀模式
想用PCF8591進(jìn)行AD轉(zhuǎn)換并將轉(zhuǎn)換的數(shù)傳入到單片機(jī)中,顯示在LCD1602液晶屏上,但是并不能得到數(shù)據(jù),顯示也不能進(jìn)行,顯示情況即為在初始位置不斷閃爍。本人大學(xué)生,想用單片機(jī)做一個(gè)散射式濁度計(jì),因此需要將檢測的光強(qiáng)顯示在液晶上,但無奈因?yàn)橹安⑽唇佑|過單片機(jī),所以一直找不到頭緒到底錯(cuò)在了哪里,還請各位大神指教。下面附上代碼,代碼也是我東拼西湊的,因?yàn)樽罱容^著急這個(gè)事,請問大家對如何寫有什么好建議嗎,是一邊模仿一邊學(xué)習(xí)還是如何呢。
#ifndef _I2C_H_
#define _I2C_H_

extern bit ack;
//起動(dòng)總線函數(shù)
extern void Start_I2c();
//結(jié)束總線函數(shù)  
extern void Stop_I2c();
//應(yīng)答子函數(shù)
extern void Ack_I2c(bit a);
//字節(jié)數(shù)據(jù)發(fā)送函數(shù)
extern void  SendByte(unsigned char  c);
//有子地址發(fā)送多字節(jié)數(shù)據(jù)函數(shù)               
extern bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no) ;
//無子地址發(fā)送多字節(jié)數(shù)據(jù)函數(shù)   
extern bit ISendStrExt(unsigned char sla,unsigned char *s,unsigned char no);
//無子地址讀字節(jié)數(shù)據(jù)函數(shù)               
extern unsigned char RcvByte();



#endif

/*************************此部分為I2C總線的驅(qū)動(dòng)程序*************************************/

#include <reg52.h>
#include <intrins.h>
#include <I2C.H>

#define  NOP()   _nop_()   /* 定義空指令 */
#define  _Nop()  _nop_()   /*定義空指令*/


sbit     SCL=P2^1;       //I2C  時(shí)鐘
sbit     SDA=P2^0;       //I2C  數(shù)據(jù)
bit ack;                 /*應(yīng)答標(biāo)志位*/


/*******************************************************************
                     起動(dòng)總線函數(shù)               
函數(shù)原型: void  Start_I2c();  
功能:     啟動(dòng)I2C總線,即發(fā)送I2C起始條件.  
********************************************************************/
void Start_I2c()
{
  SDA=1;         /*發(fā)送起始條件的數(shù)據(jù)信號*/
  _Nop();
  SCL=1;
  _Nop();        /*起始條件建立時(shí)間大于4.7us,延時(shí)*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();   
  SDA=0;         /*發(fā)送起始信號*/
  _Nop();        /* 起始條件鎖定時(shí)間大于4μs*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();      
  SCL=0;       /*鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù) */
  _Nop();
  _Nop();
}

/*******************************************************************
                      結(jié)束總線函數(shù)               
函數(shù)原型: void  Stop_I2c();  
功能:     結(jié)束I2C總線,即發(fā)送I2C結(jié)束條件.  
********************************************************************/
void Stop_I2c()
{
  SDA=0;      /*發(fā)送結(jié)束條件的數(shù)據(jù)信號*/
  _Nop();       /*發(fā)送結(jié)束條件的時(shí)鐘信號*/
  SCL=1;      /*結(jié)束條件建立時(shí)間大于4μs*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  SDA=1;      /*發(fā)送I2C總線結(jié)束信號*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();
}

/*******************************************************************
                 字節(jié)數(shù)據(jù)發(fā)送函數(shù)               
函數(shù)原型: void  SendByte(UCHAR c);
功能:     將數(shù)據(jù)c發(fā)送出去,可以是地址,也可以是數(shù)據(jù),發(fā)完后等待應(yīng)答,并對
          此狀態(tài)位進(jìn)行操作.(不應(yīng)答或非應(yīng)答都使ack=0)     
           發(fā)送數(shù)據(jù)正常,ack=1; ack=0表示被控器無應(yīng)答或損壞。
********************************************************************/
void  SendByte(unsigned char  c)
{
        unsigned char  BitCnt;

        for(BitCnt=0;BitCnt<8;BitCnt++)  /*要傳送的數(shù)據(jù)長度為8位*/
        {
                if((c<<BitCnt)&0x80)SDA=1;   /*判斷發(fā)送位*/
                else  SDA=0;               
                        _Nop();
                SCL=1;               /*置時(shí)鐘線為高,通知被控器開始接收數(shù)據(jù)位*/
                        _Nop();
                        _Nop();             /*保證時(shí)鐘高電平周期大于4μs*/
                        _Nop();
                        _Nop();
                        _Nop();         
                SCL=0;
    }

                _Nop();
                _Nop();
    SDA=1;                /*8位發(fā)送完后釋放數(shù)據(jù)線,準(zhǔn)備接收應(yīng)答位*/
                _Nop();
                _Nop();   
    SCL=1;
                _Nop();
                _Nop();
                _Nop();
    if(SDA==1)ack=0;     
       else ack=1;        /*判斷是否接收到應(yīng)答信號*/
    SCL=0;
                _Nop();
                _Nop();
}

/*******************************************************************
                 字節(jié)數(shù)據(jù)接收函數(shù)               
函數(shù)原型: UCHAR  RcvByte();
功能:        用來接收從器件傳來的數(shù)據(jù),并判斷總線錯(cuò)誤(不發(fā)應(yīng)答信號),
          發(fā)完后請用應(yīng)答函數(shù)應(yīng)答從機(jī)。  
********************************************************************/   
unsigned char   RcvByte()
{
  unsigned char  retc;
  unsigned char  BitCnt;

  retc=0;
  SDA=1;                     /*置數(shù)據(jù)線為輸入方式*/
  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        _Nop();           
        SCL=0;                  /*置時(shí)鐘線為低,準(zhǔn)備接收數(shù)據(jù)位*/
        _Nop();
        _Nop();                 /*時(shí)鐘低電平周期大于4.7μs*/
        _Nop();
        _Nop();
        _Nop();
        SCL=1;                  /*置時(shí)鐘線為高使數(shù)據(jù)線上數(shù)據(jù)有效*/
        _Nop();
        _Nop();
        retc=retc<<1;
        if(SDA==1)retc=retc+1;  /*讀數(shù)據(jù)位,接收的數(shù)據(jù)位放入retc中 */
        _Nop();
        _Nop();
      }
  SCL=0;   
  _Nop();
  _Nop();
  return(retc);
}

/********************************************************************
                     應(yīng)答子函數(shù)
函數(shù)原型:  void Ack_I2c(bit a);
功能:      主控器進(jìn)行應(yīng)答信號(可以是應(yīng)答或非應(yīng)答信號,由位參數(shù)a決定)
********************************************************************/
void Ack_I2c(bit a)
{

  if(a==0)SDA=0;              /*在此發(fā)出應(yīng)答或非應(yīng)答信號 */
  else SDA=1;
  _Nop();
  _Nop();
  _Nop();      
  SCL=1;
  _Nop();
  _Nop();                    /*時(shí)鐘低電平周期大于4μs*/
  _Nop();
  _Nop();
  _Nop();  
  SCL=0;                     /*清時(shí)鐘線,鉗住I2C總線以便繼續(xù)接收*/
  _Nop();
  _Nop();   
}



#ifndef __LCD_H_
#define __LCD_H_
/**********************************
當(dāng)使用的是4位數(shù)據(jù)傳輸?shù)臅r(shí)候定義,
使用8位取消這個(gè)定義
**********************************/
//#define LCD1602_4PINS

/**********************************
包含頭文件
**********************************/
#include<reg52.h>

//---重定義關(guān)鍵詞---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif

/**********************************
PIN口定義
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;

/**********************************
函數(shù)聲明
**********************************/
/*在51單片機(jī)12MHZ時(shí)鐘下的延時(shí)函數(shù)*/
void Lcd1602_Delay1ms(uint c);   //誤差 0us
/*LCD1602寫入8位命令子函數(shù)*/
void LcdWriteCom(uchar com);
/*LCD1602寫入8位數(shù)據(jù)子函數(shù)*/        
void LcdWriteData(uchar dat)        ;
/*LCD1602初始化子程序*/               
void LcdInit();                                                  

#endif


#include"lcd.h"

/*******************************************************************************
* 函 數(shù) 名         : Lcd1602_Delay1ms
* 函數(shù)功能                   : 延時(shí)函數(shù),延時(shí)1ms
* 輸    入         : c
* 輸    出         : 無
* 說    名         : 該函數(shù)是在12MHZ晶振下,12分頻單片機(jī)的延時(shí)。
*******************************************************************************/

void Lcd1602_Delay1ms(uint c)   //誤差 0us
{
    uchar a,b;
        for (; c>0; c--)
        {
                 for (b=199;b>0;b--)
                 {
                          for(a=1;a>0;a--);
                 }      
        }
            
}

/*******************************************************************************
* 函 數(shù) 名         : LcdWriteCom
* 函數(shù)功能                   : 向LCD寫入一個(gè)字節(jié)的命令
* 輸    入         : com
* 輸    出         : 無
*******************************************************************************/
#ifndef         LCD1602_4PINS         //當(dāng)沒有定義這個(gè)LCD1602_4PINS時(shí)
void LcdWriteCom(uchar com)          //寫入命令
{
        LCD1602_E = 0;     //使能
        LCD1602_RS = 0;           //選擇發(fā)送命令
        LCD1602_RW = 0;           //選擇寫入
        
        LCD1602_DATAPINS = com;     //放入命令
        Lcd1602_Delay1ms(1);                //等待數(shù)據(jù)穩(wěn)定

        LCD1602_E = 1;                  //寫入時(shí)序
        Lcd1602_Delay1ms(5);          //保持時(shí)間
        LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com)          //寫入命令
{
        LCD1602_E = 0;         //使能清零
        LCD1602_RS = 0;         //選擇寫入命令
        LCD1602_RW = 0;         //選擇寫入

        LCD1602_DATAPINS = com;        //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
        Lcd1602_Delay1ms(1);

        LCD1602_E = 1;         //寫入時(shí)序
        Lcd1602_Delay1ms(5);
        LCD1602_E = 0;

//        Lcd1602_Delay1ms(1);
        LCD1602_DATAPINS = com << 4; //發(fā)送低四位
        Lcd1602_Delay1ms(1);

        LCD1602_E = 1;         //寫入時(shí)序
        Lcd1602_Delay1ms(5);
        LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 數(shù) 名         : LcdWriteData
* 函數(shù)功能                   : 向LCD寫入一個(gè)字節(jié)的數(shù)據(jù)
* 輸    入         : dat
* 輸    出         : 無
*******************************************************************************/                  
#ifndef         LCD1602_4PINS                  
void LcdWriteData(uchar dat)                        //寫入數(shù)據(jù)
{
        LCD1602_E = 0;        //使能清零
        LCD1602_RS = 1;        //選擇輸入數(shù)據(jù)
        LCD1602_RW = 0;        //選擇寫入

        LCD1602_DATAPINS = dat; //寫入數(shù)據(jù)
        Lcd1602_Delay1ms(1);

        LCD1602_E = 1;   //寫入時(shí)序
        Lcd1602_Delay1ms(5);   //保持時(shí)間
        LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat)                        //寫入數(shù)據(jù)
{
        LCD1602_E = 0;          //使能清零
        LCD1602_RS = 1;          //選擇寫入數(shù)據(jù)
        LCD1602_RW = 0;          //選擇寫入

        LCD1602_DATAPINS = dat;        //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
        Lcd1602_Delay1ms(1);

        LCD1602_E = 1;          //寫入時(shí)序
        Lcd1602_Delay1ms(5);
        LCD1602_E = 0;

        LCD1602_DATAPINS = dat << 4; //寫入低四位
        Lcd1602_Delay1ms(1);

        LCD1602_E = 1;          //寫入時(shí)序
        Lcd1602_Delay1ms(5);
        LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 數(shù) 名       : LcdInit()
* 函數(shù)功能                 : 初始化LCD屏
* 輸    入       : 無
* 輸    出       : 無
*******************************************************************************/                  
#ifndef                LCD1602_4PINS
void LcdInit()                                                  //LCD初始化子程序
{
         LcdWriteCom(0x38);  //開顯示
        LcdWriteCom(0x0c);  //開顯示不顯示光標(biāo)
        LcdWriteCom(0x06);  //寫一個(gè)指針加1
        LcdWriteCom(0x01);  //清屏
        LcdWriteCom(0x80);  //設(shè)置數(shù)據(jù)指針起點(diǎn)
}
#else
void LcdInit()                                                  //LCD初始化子程序
{
        LcdWriteCom(0x32);         //將8位總線轉(zhuǎn)為4位總線
        LcdWriteCom(0x28);         //在四位線下的初始化
        LcdWriteCom(0x0c);  //開顯示不顯示光標(biāo)
        LcdWriteCom(0x06);  //寫一個(gè)指針加1
        LcdWriteCom(0x01);  //清屏
        LcdWriteCom(0x80);  //設(shè)置數(shù)據(jù)指針起點(diǎn)
}
#endif



#include "reg52.h"
#include "lcd.h"
#include "I2C.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define READADDR 0x91;
#define WRITEADDR 0x90;

u8 hehe[5]="nihao";




void delay(u16 i)
{
        while(i--);
}

void Pcf8591SendByte(uchar channel)
{   
    Start_I2c();   
    SendByte(0x91);        
    SendByte(0x40|channel);     
    Stop_I2c();
}

u8 Pcf8591ReadByte()
{
    uchar num;
    Start_I2c();
    SendByte(0x90);      //???????
    num = RcvByte();          //????
    Stop_I2c();                  //????
    return num;
}



void main()
{
        u16 i,dat;
        u8 dat;
        Pcf8591SendByte(0x40);
        dat=Pcf8591ReadByte();
        LcdInit();
        LcdWriteCom(0x80);
        LcdWriteData(dat);
        

        
}


還請各位大神指教,有償也行的,是真的想了解到底為什么錯(cuò)了,錯(cuò)在哪里,我有什么做的不對的地方請各位大神指教。

全部資料51hei下載地址:
LCD顯示AD轉(zhuǎn)換結(jié)果.rar (17.08 KB, 下載次數(shù): 13)




回復(fù)

使用道具 舉報(bào)

ID:508775 發(fā)表于 2019-4-17 09:03 | 顯示全部樓層
請各位大佬指教啊。
回復(fù)

使用道具 舉報(bào)

ID:213173 發(fā)表于 2019-4-17 18:14 | 顯示全部樓層
892494590 發(fā)表于 2019-4-17 09:03
請各位大佬指教啊。

何不使用STC15系列有內(nèi)置AD轉(zhuǎn)換的MCU,只要外接一個(gè)光敏電阻采樣即可。
回復(fù)

使用道具 舉報(bào)

ID:158375 發(fā)表于 2019-4-18 13:37 | 顯示全部樓層
一次不要寫太多程序,可以分開寫程序調(diào)試;
例如,不加PCF8591,先把單片機(jī)和顯示弄出來,你想顯示什么,就能顯示什么,就是很大的提高啦。
然后再說PCF8591數(shù)模轉(zhuǎn)換問題以及顯示計(jì)算等等。。。
回復(fù)

使用道具 舉報(bào)

ID:508775 發(fā)表于 2019-4-18 17:28 | 顯示全部樓層
wulin 發(fā)表于 2019-4-17 18:14
何不使用STC15系列有內(nèi)置AD轉(zhuǎn)換的MCU,只要外接一個(gè)光敏電阻采樣即可。

因?yàn)槲抑安⑽唇佑|過單片機(jī)這些,因?yàn)檫@邊有個(gè)小項(xiàng)目最近才接觸,并不是懂很多,您的建議我會去看看的,謝謝您了。
回復(fù)

使用道具 舉報(bào)

ID:508775 發(fā)表于 2019-4-18 17:30 | 顯示全部樓層
笨笨兔 發(fā)表于 2019-4-18 13:37
一次不要寫太多程序,可以分開寫程序調(diào)試;
例如,不加PCF8591,先把單片機(jī)和顯示弄出來,你想顯示什么,就 ...

嗯,您說的對,想請問您對串口通信了解嗎。
回復(fù)

使用道具 舉報(bào)

ID:508775 發(fā)表于 2019-4-18 17:33 | 顯示全部樓層
wulin 發(fā)表于 2019-4-17 18:14
何不使用STC15系列有內(nèi)置AD轉(zhuǎn)換的MCU,只要外接一個(gè)光敏電阻采樣即可。

我們做的項(xiàng)目也不是很高端,如果是STC15系列,您有什么推薦呢,我們這邊是學(xué)生,經(jīng)費(fèi)有限。
回復(fù)

使用道具 舉報(bào)

ID:508775 發(fā)表于 2019-4-18 17:43 | 顯示全部樓層
wulin 發(fā)表于 2019-4-17 18:14
何不使用STC15系列有內(nèi)置AD轉(zhuǎn)換的MCU,只要外接一個(gè)光敏電阻采樣即可。

我們要做一個(gè)散射式濁度計(jì),但是傳感器不入水,所以對光的收集之類的要求比較高,就沒用光敏電阻,直接買的照度計(jì)模塊。
回復(fù)

使用道具 舉報(bào)

ID:508775 發(fā)表于 2019-4-18 17:43 | 顯示全部樓層
謝謝各位的回答,小白在這里受教了哈哈。
回復(fù)

使用道具 舉報(bào)

ID:213173 發(fā)表于 2019-4-18 21:42 | 顯示全部樓層
892494590 發(fā)表于 2019-4-18 17:43
我們要做一個(gè)散射式濁度計(jì),但是傳感器不入水,所以對光的收集之類的要求比較高,就沒用光敏電阻,直接買 ...

PCF8591照度模塊上面一樣還是用的光敏電阻,不過也不貴。用STC15W408AS加光敏電阻就更省錢。
無標(biāo)題.jpg

回復(fù)

使用道具 舉報(bào)

ID:158375 發(fā)表于 2019-4-19 08:44 | 顯示全部樓層
892494590 發(fā)表于 2019-4-18 17:30
嗯,您說的對,想請問您對串口通信了解嗎。

對串口了解一點(diǎn),有什么要說的就直接說好了。
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表