************** 電壓 P0.0電壓采集 可以測試0-5V的外部電壓值 用1602顯示*************
//////////////////////// /***********************************************************************
/* LCD1602
LCD1602顯示 rs P3^5 rw P3^6 ep P3^7 P2口 為數據輸出口
***********************************************************************///////////////////////
************** STC12 ADC電壓采集測試程序 *************/
#include <reg52.H>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
uchar Vo; //A/D轉換後換算的電壓值
int i,e;
/*Define ADC operation const for ADC_CONTR*/
#define ADC_POWER 0x80 //ADC power control bit
#define ADC_FLAG 0x10 //ADC complete flag 模數轉換結束標誌位
#define ADC_START 0x08 //ADC start control bit 模數轉換啟動控制位
//轉換速度控制位SPEED0和SPEED1,***四種狀態,對應四種轉換速度
#define ADC_SPEEDLL 0x00 //540 clocks
#define ADC_SPEEDL 0x20 //360 clocks
#define ADC_SPEEDH 0x40 //180 clocks
#define ADC_SPEEDHH 0x60 //90 clocks
sbit rw=P3^6; //1602 IO口定義 這裏用的數據口是P2口
sbit rs=P3^5;
sbit ep=P3^7;
uchar code asc[] = "0123456789";
unsigned char code d[] = {"ADC Test"};
unsigned char code a[] ={ //漢字
0x04,0x1f,0x15,0x1f,0x15,0x1f,0x05,0x07, //電
0x0f,0x08,0,0,0x0f,0,0x13,0x0f, //壓
};
/**************************** 延時函數 ***********************************/
void delay(unsigned int a)
{
while(a--);
}
/*----------------------------
Get ADC result
----------------------------*/
uchar GetADCResult(uchar ch) //這裏如有不懂 請仔細看資料
{
P1ASF = 0x01; //選擇P1口的哪壹口 這裏的口和ch要對應才能達到選擇該口
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;//0x00|0x00|ch|0x08:選擇A/D輸入通道,開始A/D轉換
// 這麽用語句的主要原因就是不能位尋址
// 通道選擇在後3位所以直接用壹個整數表示ch
//例如ch=6 那麽對應的後三位就是110
_nop_(); //Must wait before inquiry ,
_nop_(); //設置ADC_CONTR寄存器後需加4個CPU時鐘周期的延時,才能保證值被寫入ADC_CONTR寄存器
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag
ADC_CONTR &= ~ADC_FLAG; //Close ADC 將標誌位清零等待下次硬件置1
//也可以寫成 ADC_CONTR= ADC_CONTR & ( ~ADC_FLAG)
Vo=ADC_RES*5*10/256; //Return ADC result(為顯示整數,這裏將電壓值擴大了十倍)
//5/256 因為是8位 把5V分成256份 ADC_RES為采集的份數
//ADC_RES*(5/256) 為采集的電壓值 然後擴大10倍便於計算
return Vo;
}
/*************************************************************************************/
/*************************************************************************************/
/***************************** 1602 *******************************************/
bit lcd_busy() //查忙 這部很重要 否則有的顯示容易出現亂碼
{
bit result;
rs = 0;
rw = 1;
ep = 1;
delay(50);
result = (bit)(P2&0x80);
ep = 0;
return result; //返回值
}
void lcd_com(unsigned char com)// 地址
{
while(lcd_busy());
rs=0;
ep=0;
rw=0;
P2=com;
delay(50);
ep=1;
delay(50);
ep=0;
}
void lcd_date(unsigned char date)//采集輸出數據
{
while(lcd_busy());
rs=1; //1是些數據 0是寫指令
rw=0; // 1是讀 0是寫
ep=0; //E端為使能端,當E端由高電平跳變成低電平時,液晶模塊執行命令
P2=date;
delay(5);
ep=1;
delay(5);
ep=0;
}
void lcd_pos(unsigned char pos)
{
lcd_com(pos|0x80); //數據指針=80+地址變量
}
void writetab() // 寫 漢字函數
{
unsigned char m;
lcd_com(0x40); //寫CGRAM 此處是指令
for (m = 0; m<16; m++)
lcd_date(a[m]);
}
void init()//1602初始化
{
lcd_com(0x38);
delay(50);
lcd_com(0x38);
delay(50);
lcd_com(0x38);
delay(50);
lcd_com(0x0c);
delay(50);
lcd_com(0x06);
delay(50);
lcd_com(0x01);
delay(2000);
writetab() ; // 漢字初始化
}
/*******************************************************************************/
/*******************************************************************************/
/*******************************************************************************/
void hanzi() //漢字顯示
{
lcd_pos(0x40); //電壓
lcd_date(0x00);
lcd_pos(0x40+1);
lcd_date(0x01);
}
/************************************************************************/
void main(void)
{
TMOD=0x01; //選擇定時器T0 在工作方式1上 即16位定時器
TH0=(65536-50000)/256; //11.592M晶振的壹個機器周期接近1us 這裏5W就是0.05s
TL0=(65536-50000)%256;
EA=1; //開啟總中斷
ET0=1; //開啟定時器T0
TR0=1; // 啟動定時器 使其開始計算
init(); //1602初始化
lcd_pos(0x00); //顯示字母
i=0;
while(d[i]!='\0')
{
lcd_date(d[i]);
i++;
}
hanzi(); //顯示漢字
delay(300);
while(1)
{
lcd_pos(0x42);
lcd_date(':');
lcd_date(asc[Vo/10]);
lcd_date('.');
lcd_date(asc[Vo%10]);
lcd_date('V');
}
}
void ADCt0() interrupt 1
{
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
e++;
if(e==20)
{ e=0;
GetADCResult(0);
}
}