ADC0832模數轉換和LCD顯示

環境

軟件

  • uVision V4.02
  • ISIS Professional 7.8

芯片

  • AT89C51
  • ADC0832

仿真圖

在這裏插入圖片描述

實現效果

顯示電壓值並用圖標顯示百分比
具體效果如下所示:
在這裏插入圖片描述

相關代碼及資源

https://github.com/duganlx/DSP

操作小記

芯片介紹

接口說明

  • CS:片選使能,低電平芯片使能
  • CH0:模擬輸入通道0,或作爲IN+/-使用
  • CH1:模擬輸入通道0,或作爲IN+/-使用
  • GND:芯片參考0電位(地)
  • DI:數據信號輸入,選擇通道控制
  • DO:數據信號輸出,轉換數據輸出
  • CLK:芯片時鐘輸入
  • VCC/REF:電源輸入及參考電壓輸入(複用)

ADC0832 爲 8 位分辨率 A/D 轉換芯片,其最高分辨可達256 級,可以適應一般的模擬量轉換要求。其內部電源輸入與參考電壓的複用,使得芯片的模擬電壓輸入0~5V 之間。芯片轉換時間僅爲 32μS,具有雙數據輸出可作爲數據校驗,以減少數據誤差,轉換速度快且穩定性能強。獨立的芯片使能輸入,使多器件掛接和處理器控制變的更加方便。通過** DI 數據輸入端**,可以輕易的實現通道功能的選擇

單片機控制原理

正常情況下,ADC0832與單片機的接口應爲4條數據線,分別是CSCLKDODI。但由於DO端與DI端在通信時並未同時有效並與單片機的接口是雙向的,所以電路設計時可以將DODI並聯在一個數據線上使用。在這裏插入圖片描述
當ADC0832 未工作時,其CS輸入端應爲高電平,此時芯片禁用CLKDO/DI的電平任意
進行A/D轉換時,須先將CS使能端置於低電平並且保持低電平直到轉換完全結束。此時芯片開始轉換工作,同時由處理器向芯片時鐘輸入端CLK輸入時鐘脈衝,DO/DI端則使用DI端輸入通道功能選擇的數據信號。

  • 第1個時鐘脈衝的下沉之前DI端必須是高電平,表示啓動信號
  • 第2、3個脈衝下沉之前DI端應輸入2位數據用於選擇通道功能,具體如下圖所示:

在這裏插入圖片描述
如上圖所示:

  • 當兩位數據爲10時,只對CH0進行單通道轉換
  • 當兩位數據爲11時,只對CH1進行單通道轉換
  • 當兩位數據爲00時,將CH0作爲正輸入端IN+,將CH1作爲負輸入端IN-
  • 當兩位數據爲01時,將CH0作爲負輸入端IN-,將CH1作爲正輸入端IN+
  • 第3個脈衝的下沉之後DI端的輸入電平失去輸入作用,此時DO/DI端則開始利用數據輸出DO進行轉換數據的讀取
  • 第4個脈衝下沉開始DO端輸出轉換數據最高位DATA7,隨後每一個脈衝下沉DO端輸出下一位數據
  • 直到第11個脈衝時發出最低位數據DATA0一個字節的數據輸出完成
  • 也從第11個脈衝開始輸出下一個相反字節的數據,即從第11個脈衝的下沉輸出DATA0
  • 隨後輸出8位數據,直到第19個脈衝時數據輸出完成,也標誌一次A/D轉換的結束
  • CS高電平禁用芯片,直接將轉換後的數據進行處理就可以了
時序圖

在這裏插入圖片描述

代碼編寫

引用庫文件

#include<reg51.h>
#include<string.h>
#include<intrins.h>

宏定義

#define Uint unsigned int
#define Uchar unsigned char

全局變量定義

//對應仿真圖中引腳的對接
sbit CS=P1^0; // chip select
sbit CLK=P1^1; // clock
sbit DIO=P1^2; // data input and output
sbit RS=P2^0; // data register status register
sbit RW=P2^1; // read/write
sbit EN=P2^2; // enable

Uchar disp_buff1[]="VOLTAGE:  0.00V";
Uchar disp_buff2[16];

延時函數

/*
* 延時2微秒
* 
* @return
*/
void delay2us()
{
	_nop_();
	_nop_();
}

AD轉換

/*
* AD轉換
*
* @return 輸出數據
*/
Uchar get_AD_Res()
{
	Uchar i, data1=0, data2=0;
	CS=0;
	//第一個週期:轉換開始
	CLK=0;DIO=1;delay2us();
	CLK=1;delay2us();
	
	//第二個週期:選擇單通道還是雙通道 DIO=0雙通道差分 或 DIO=1單通道
	CLK=0;DIO=1;delay2us(); 
	CLK=1;delay2us();
	
	//第三個週期:DIO選擇CH1-->如果DIO=0 選擇CH0
	CLK=0;DIO=0;delay2us();
	CLK=1;delay2us();
	
	//等待
	CLK=0;DIO=1;delay2us(); 
	
	//先進來的爲最高位,後進來爲最低位
	for(i=0; i<8; i++)
	{
		CLK=1;delay2us();
		CLK=0;delay2us();
		/*
		* 0000_0000|0000_000想=0000_000想
		* 0000_00想0|0000_000翔=0000_00想翔
		* 0000_0想翔0|0000_000子=0000_0想翔子
		*/
		data1=(data1<<1)|(Uchar)DIO; 
	}
	
	//先進來的爲最低位,後進來爲最高位
	for(i=0; i<8; i++)
	{
		/*
		* 0000_0000|0000_000子=0000_000子
		* 0000_000子|0000_00翔0=0000_00翔子
		* 0000_00翔子|0000_0想00=0000_0想翔子
		*/
		data2= data2|(Uchar)DIO<<i;
		CLK=1;delay2us();
		CLK=0;delay2us();
		 
	}
	
	//禁止片選
	CS=1;
	
	return (data1==data2)?data1:0;
}

lcd相關函數

lcd具體用法及函數說明可以參看:1602字符液晶顯示

/*
* 延時
*  
* @param x 時間(不精確)
* @return
*/
void delay_ms(Uint x)
{
	Uchar t;
	while(x--)
		for(t=0; t<120; t++);
}

/*
* 檢測BF(busy flag)位狀態
* 
* @return
*/
bit test_BF()
{
	Uchar LCD_status;
	P0=0xFF;
	EN=0;RS=0;RW=1;
	EN=1;delay2us();LCD_status=P0;
	EN=0;
	return (LCD_status&0x80)?1:0;
}

/*
* 寫命令
*
* @param cmd 八位命令
* @return
*/
void write_CMD(Uchar cmd)
{
	while(test_BF());
	EN=0; RS=0; RW=0;
	P0=cmd;
	EN=1; _nop_(); EN=0;
}

/*
* 寫數據(一位一位的寫)
*
* @param data8 八位數據
* @return
*/
void write_Data(Uchar data8)
{
	while(test_BF());
	EN=0; RS=1; RW=0;
	P0=data8;
	EN=1; _nop_(); EN=0;
}

/*
* 初始化
*
* @return
*/
void init()
{
	write_CMD(0x38);delay_ms(1);
	write_CMD(0x01);delay_ms(1);
	write_CMD(0x06);delay_ms(1);
	write_CMD(0x0C);delay_ms(1);
}

/*
* 寫字符串
*
* @param r row
* @param c column
* @param str 字符串
* @return
*/
void write_Str(int r, int c, char *str)
{
	int i=0;	
	unsigned char Addressx[] = {0x80, 0xC0};
	unsigned char StartAdd = (Addressx[r] | c);//按位或

	write_CMD(StartAdd);
	
	for(i = 0; i < 16; i++){
		if(str[i]==0) break;
		write_Data(str[i]);
	}
	// 如果不夠16位,用空格填充
	for(;i < 16; i++){
		write_Data(' '); 	
	}
}

主函數

void main()
{
	Uchar i=0,AD=0;
	Uint d=0;
	init();
	
	while(1)
	{
		AD=get_AD_Res(); 
		d=(AD*500.0/256.0); //d需Uint 
		
		disp_buff1[10]=d/100+'0';
		disp_buff1[12]=(d/10)%10+'0';
		disp_buff1[13]=d%10+'0';
		
		write_Str(0,0,disp_buff1);
		
		//填充實心和空心的框框
		i=(Uint)AD*16/256;
		memset(disp_buff2,'\xFF',i);
		memset(disp_buff2+i,'\xDB',16-i);
		write_Str(1,0,disp_buff2);
	}
	
}
發佈了116 篇原創文章 · 獲贊 58 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章