<pre name="code" class="csharp">/*
專案名稱:PCF8591AD和串列埠列印
專案內容:A/D轉換,把轉換的數字量
送給P0口控制LED的亮滅 ;
並把轉換的數字邏輯
運算,送給串列埠,列印到電腦上。
這樣就可以取樣電壓訊號了,並處理。
可以擴充套件做出電壓表,電流表等。
作者:YUAN
*/
#include <reg52.h>
#include <stdio.h> //printf輸出標頭檔案
#include <intrins.h> //_nop_()延時標頭檔案
typedef unsigned char uChar8;
typedef unsigned int uInt16;
sbit SDA = P1^0;
sbit SCL = P1^1;
#define PCF8591Add 0x90 //PCF8591的器件地址和寫操作
uChar8 gTemp;
float gfDataVal; //用在轉載計算的數值,併傳送給計算機
//延時函式
void DelayMS(uInt16 lValMS);
void Delay5us(void);
//IIC操作的幾個函式
void IICInit(void); //IIC初始化
void IICStart(void); //起始訊號
void IICStop(void); //停止訊號
void IICAck(void); //應答訊號
void IICReadAck(void); //讀應答訊號
void IICWriteOneByte(uChar8 lByteVal); //寫一個位元組
uChar8 IICReadOneByte(void); //讀一個位元組
void PCF8591WriteRegulate(uChar8 lREGVal); //Regulate控制器,這裡寫控制函式
uChar8 ReadDataPCF8591(void);
//
//串列埠的幾個程式
void UartInit(void); //串列埠初始化
void UartPrint(float iVal); //Printd列印,列印函式
void main()
{
IICInit();
UartInit();
while(1)
{
/*寫入控制字00,即模擬量輸出關閉,選擇通道0,
不自動增加通道,模擬量輸入圍方式0*/
PCF8591WriteRegulate(0x00);
P0 = ReadDataPCF8591();
gTemp = P0; //用來中轉的儲存區
gfDataVal = (float)gTemp/255*5; //強制轉換
DelayMS(1000);
UartPrint(gfDataVal);
}
}
void DelayMS(uInt16 lValMS) //延時函式
{
uInt16 luiVal,lujVal;
for(luiVal = 0; luiVal < lValMS; luiVal++)
for(lujVal = 0; lujVal < 113; lujVal++);
}
void Delay5us(void)
{
_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
}
//IIC匯流排空閒時均為高電平
void IICInit(void) //IIC初始化
{
SCL = 0;
SDA=1;
Delay5us();
SCL=1;
}
//SCL高電平期間SDA由高到低的變化為起始訊號
void IICStart(void) //起始訊號
{
SCL = 0;
Delay5us();
SDA = 1;
Delay5us();
SCL = 1;
Delay5us();
SDA = 0;
Delay5us();
//防止接下來SDA資料變化導致IIC匯流排誤判
SCL = 0;
}
//SCL高電平期間SDA由低到高的變化為終止訊號
void IICStop(void) //停止訊號
{
SCL = 0;
Delay5us();
SDA = 0;
Delay5us();
SCL = 1;
Delay5us();
SDA = 1;
Delay5us();
//防止接下來SDA資料變化導致IIC匯流排誤判
SCL = 0;
}
//一個脈衝期間,SDA為低電平為應答
void IICAck(void) //應答訊號
{
SCL = 0;
Delay5us();
SDA = 0;
Delay5us();
SCL = 1;
Delay5us();
SCL = 0;
}
/*cpu讀應答訊號,如果應答了則
繼續傳輸資料,否則在一定時間裡,
預設已經應答,繼續傳資料
*/
void IICReadAck(void) //讀應答訊號
{
uChar8 li = 0;
SCL = 0;
SDA = 1; //確保讀出的值為0,因此先送1
Delay5us();
SCL = 1;
Delay5us();
//如果沒有應答或時間沒有超過預定時間則停在此處
while((1 == SDA)&&(li<255))li++;
SCL = 0;
Delay5us();
SDA = 1;
}
/*
寫1個位元組,先寫高位。
*/
void IICWriteOneByte(uChar8 lByteVal) //寫一個位元組
{
uChar8 li,liVal;
liVal = lByteVal;
for(li=0;li<8;li++)
{
SCL = 0;
Delay5us();
SDA = (bit)(liVal&0x80); //把資料準備好等待傳送
Delay5us();
SCL = 1;
Delay5us();
liVal <<= 1;
}
SCL = 0;
Delay5us();
SDA = 1;
}
/*
讀取一個位元組並把讀到的值返回
*/
uChar8 IICReadOneByte(void)
{
uChar8 li,liVal;
SCL = 0;
SDA = 1;
for(li=0;li<8;li++)
{
liVal <<= 1;
SCL = 0;
Delay5us();
SCL = 1;
Delay5us();
liVal = (liVal|SDA);
}
SCL = 0;
return liVal;
}
//Regulate控制器,這裡寫控制函式
void PCF8591WriteRegulate(uChar8 lREGVal)
{
IICStart();
IICWriteOneByte(PCF8591Add); //PCF8591的地址,寫控制
IICReadAck();
IICWriteOneByte(lREGVal); //寫入控制字
IICReadAck();
IICStop();
}
uChar8 ReadDataPCF8591(void)
{
uChar8 liVal;
IICStart();
IICWriteOneByte(PCF8591Add|0x01); //PCF8591的地址,讀控制
liVal = IICReadOneByte();
IICAck();
IICStop();
return liVal;
}
//串列埠的程式
void UartInit(void)
{
TMOD &= 0x0f; //只改變要改變的
TMOD |= 0x20; //設定定時器0為工作方式2
TL1 = 0xfd;
TH1 = 0xfd; //設定波特率為9600bps
TR1 = 1; //允許T1開始計數
SCON &= 0x5f;
SCON |= 0x50; //設定串列埠工作在方式1,允許接收資料
}
//把讀出來的值列印到計算機上
void UartPrint(float iVal)
{
TI=1;
printf("測得電壓為:%f\n",iVal);
while(!TI);
TI=0;
}