前述:
QQ:3177227373
這個是一個簡易課設作品。
資源鏈接:資源鏈接(點擊藍色字體即可跳轉,包含代碼工程和PCB)
單片機介紹:
8位CPU·4kbytes程序存儲器(ROM) (52爲8K)
128bytes的數據存儲器(RAM) (52有256bytes的RAM)
32條I/O口線,111條指令,大部分爲單字節指令
21個專用寄存器
2個可編程定時/計數器·5箇中斷源,2個優先級(52有6個)
一個全雙工串行通信口
I/O口:四個8位,並行I/O口,既可用作輸入,也可用作輸出
兩個定時器,兩個外部中斷,一個全雙工串口。
5V供電
其餘資料參考芯片手冊
芯片手冊:百度網盤鏈接 (點擊藍色字體即可跳轉)
提取碼:u0po
PCF8591芯片:
注意
如果採用其中一個通道的話是直接讀取該通道的數據,如果是採用兩個通道的話需要交換讀取數據通道口,比如用通道一和二,那麼讀取實際電路通道一的數據需要在程序中寫Dat1=Read(2);Dat2=Read(1); 這是因爲在讀取PCF8591的通道口數據的時候是上一次通道口轉換的的數據。
PCF8591是一個單片集成、單獨供電、低功耗、8-bit CMOS數據獲取器件。PCF8591具有4個模擬輸入、1個模擬輸出和1個串行I²C總線接口。PCF8591的3個地址引腳A0, A1和A2可用於硬件地址編程,允許在同個I2C總線上接入8個PCF8591器件,而無需額外的硬件。在PCF8591器件上輸入輸出的地址、控制和數據信號都是通過雙線雙向I2C總線以串行的方式進行傳輸。
【1】單獨供電
【2】PCF8591的操作電壓範圍2.5V-6V
【3】低待機電流
【4】通過I2C總線串行輸入/輸出
【5】PCF8591通過3個硬件地址引腳尋址
【6】PCF8591的採樣率由I2C總線速率決定
【7】4個模擬輸入可編程爲單端型或差分輸入
【8】自動增量頻道選擇
【9】PCF8591的模擬電壓範圍從VSS到VDD
【10】PCF8591內置跟蹤保持電路
【11】8-bit逐次逼近A/D轉換器
【12】通過1路模擬輸出實現DAC增益
實驗電路圖:
PCF8591的ADC電路:
PCB圖:
2維
3維
部分代碼:
main.c
#include<reg52.h> //包含頭文件,一般情況不需要改動,頭文件包含特殊功能寄存器的定義
#include <intrins.h> //包含NOP空指令函數_nop_();
#include<LCD1602.h>
#define AddWr 0x90 //寫數據地址
#define AddRd 0x91 //讀數據地址
sbit Sda=P2^0; //定義總線連接端口
sbit Scl=P2^1;
bit ADFlag; //定義AD採樣標誌位
void mDelay(unsigned char j); //延時程序
void Init_Timer1(void); //初始化定時器1
void Start(void); //啓動IIC總線 通信方式
void Stop(void); //停止IIC總線
void Ack(void); //應答IIC總線
void NoAck(void); //非應答IIC總線
void Send(unsigned char Data); //發送一個字節
unsigned char Read(void); //讀入一個字節並返回
unsigned char ReadADC(unsigned char Chl); //讀取AD模數轉換的值,有返回值
void DAC(unsigned char Data); //DAC輸出
void main()
{
unsigned int ADtemp,ADtemp1;//定義中間變量
InitLcd();
mDelay(20);
Init_Timer1();
while(1)
{
DAC(255); //DA輸出0,燈滅
mDelay(20); //延時用於清晰看出變化
if(ADFlag) //定時採集輸入模擬量
{
DAC(0); //輸出高,燈亮
ADFlag=0; //標誌位置0
ADtemp1=ReadADC(0); //讀取通道1
TempData[0]=(2*ADtemp1)/50; //處理0通道電壓顯示
TempData[1]=(2*ADtemp1)%50/10;
ADtemp=ReadADC(1); //讀取通道2
TempData[2]=(ReadADC(1)*2)/50;//處理1通道電壓顯示
TempData[3]=((ReadADC(1)*2)%50)/10;
ADtemp=ReadADC(2); //讀取通道3
TempData[4]=(ReadADC(2))/50;//處理1通道電壓顯示
TempData[5]=((ReadADC(2))%50)/10;
ADtemp=ReadADC(3); //讀取通道4
TempData[6]=(ReadADC(3))/50;//處理1通道電壓顯示
TempData[7]=((ReadADC(4))%50)/10;
disp(); //顯示
}
}
}
void DAC(unsigned char Data)
{
Start();
Send(AddWr); //寫入芯片地址
Ack();
Send(0x40); //寫入控制位,使能DAC輸出
Ack();
Send(Data); //寫數據
Ack();
Stop();
}
//延時程序
void mDelay(unsigned char j)
{
unsigned int i;
for(;j>0;j--)
{
for(i=0;i<125;i++)
{;}
}
}
//初始化定時器1
void Init_Timer1(void)
{
TMOD |= 0x10;
TH1=0xff; //
TL1=0x00;
EA=1;
ET1=1;
TR1=1;
}
//定時器中斷程序
void Timer1_isr(void) interrupt 3
{
static unsigned int j; //靜態變量,只初始化一次
TH1=0xfb; //重新賦值
TL1=0x00;
j++;
if(j==200)
{
j=0;
ADFlag=1; //定時置位AD採樣標誌位
}
}
//讀取AD模數轉換的值,有返回值
unsigned char ReadADC(unsigned char Chl)
{
unsigned char Data;
Start(); //寫入芯片地址
Send(AddWr);
Ack();
Send(0x40|Chl);//寫入選擇的通道,Chl的值分別爲0、1、2、3,分別代表1-4通道
Ack();
Start();
Send(AddRd); //讀入地址
Ack();
Data=Read(); //讀數據
Scl=0;
NoAck();
Stop();
return Data; //返回值
}
//讀入一個字節並返回
unsigned char Read(void)
{
unsigned char temp=0;
unsigned char temp1=0;
unsigned char BitCounter=8;
Sda=1;
do
{
Scl=0;
_nop_();
Scl=1;
_nop_();
if(Sda)
temp=temp|0x01;
else
temp=temp&0xfe;
if(BitCounter-1)
{
temp1=temp<<1;
temp=temp1;
}
BitCounter--;
}
while(BitCounter);
return(temp);
}
//啓動IIC總線
void Start(void)
{
Sda=1;
_nop_();
Scl=1;
_nop_();
Sda=0;
_nop_();
Scl=0;
}
//停止IIC總線
void Stop(void)
{
Sda=0;
_nop_();
Scl=1;
_nop_();
Sda=1;
_nop_();
Scl=0;
}
//應答IIC總線
void Ack(void)
{
Sda=0;
_nop_();
Scl=1;
_nop_();
Scl=0;
_nop_();
}
//非應答IIC總線
void NoAck(void)
{
Sda=1;
_nop_();
Scl=1;
_nop_();
Scl=0;
_nop_();
}
//發送一個字節
void Send(unsigned char Data)
{
unsigned char BitCounter=8;
unsigned char temp;
do
{
temp=Data;
Scl=0;
_nop_();
if((temp&0x80)==0x80)
Sda=1;
else
Sda=0;
Scl=1;
temp=Data<<1;
Data=temp;
BitCounter--;
}
while(BitCounter);
Scl=0;
}
1602.h
#include<reg52.h>
#include<stdio.h>
#include<intrins.h>
//1602引腳
sbit RS = P1^0; //Pin4
sbit RW = P1^1; //Pin5
sbit E = P2^5; //Pin6
#define Data P0 //數據1602數據傳送端口
unsigned char TempData[8];
unsigned char SecondLine[]=" ";//初始化位空的字符串,在讀取回來AD值以後填充
unsigned char FirstLine[] =" ";//初始化位空的字符串,在讀取回來AD值以後填充
void DelayUs(unsigned char us)//delay us
{
unsigned char uscnt;
uscnt=us>>1;
while(--uscnt);
}
/******************************************************************/
void DelayMs(unsigned char ms)//delay Ms
{
while(--ms)
{
DelayUs(250);
DelayUs(250);
DelayUs(250);
DelayUs(250);
}
}
void WriteCommand(unsigned char c)
{
DelayMs(5);//short delay before operation
E=0;
RS=0;
RW=0;
_nop_();
E=1;
Data=c;
E=0;
}
void WriteData(unsigned char c)
{
DelayMs(5); //short delay before operation
E=0;
RS=1;
RW=0;
_nop_();
E=1;
Data=c;
E=0;
RS=0;
}
void ShowChar(unsigned char pos,unsigned char c)
{
unsigned char p;
if (pos>=0x10)
p=pos+0xb0; //是第二行則命令代碼高4位爲0xc
else
p=pos+0x80; //是第二行則命令代碼高4位爲0x8
WriteCommand (p);//write command
WriteData (c); //write data
}
//顯示變量
void ShowString (unsigned char line,char *ptr)//顯示變量
{
unsigned char l,i;
l=line<<4;
for (i=0;i<16;i++)
ShowChar (l++,*(ptr+i));//循環顯示16個字符
}
//LCD初始化
void InitLcd()
{
DelayMs(15);
WriteCommand(0x38); //display mode
WriteCommand(0x38); //display mode
WriteCommand(0x38); //display mode
WriteCommand(0x06); //顯示光標移動位置
WriteCommand(0x0c); //顯示開及光標設置
WriteCommand(0x01); //顯示清屏
}
//1602顯示
void disp(void)
{
//第一行
FirstLine[2]='0'+TempData[0]; //把通道1電壓的整數部分存入FirstLine[]數組
FirstLine[3]='.'; //存入 .
FirstLine[4]='0'+TempData[1]; //把通道1電壓的小數部分存入FirstLine[]數組
FirstLine[6]='V'; //存入 V 符號
FirstLine[9] ='0'+TempData[2];
FirstLine[10]='.';
FirstLine[11]='0'+TempData[3];
FirstLine[13]='V';
//第二行
SecondLine[2]='0'+TempData[4];
SecondLine[4]='0'+TempData[5];
SecondLine[3]='.';
SecondLine[6]='V';
SecondLine[9]='0'+TempData[6];
SecondLine[11]='0'+TempData[7];
SecondLine[10]='.';
SecondLine[13]='V';
//顯示字符串
ShowString(0,FirstLine); //第一行顯示FirstLine[]字符串
ShowString(1,SecondLine); //第二行顯示SecondLine[]字符串
}