本设计基于单片机和AD转换器实现电压值的显示。采用ADC0804,实现由模拟电压转换到数字信号,通过单片机系统处理后,由LCD显示输入的电压的数值。测量范围为1.24~12V,精度大于98%。
仿真电路原理设计
软件代码设计
pwm占空比调节位于key.c文件,io口定义一般在各部分的头文件。
主函数:
#include <reg52.h>
#include "delay.h"
#include "key.h"
#include "lcd1602.h"
#include "pwm.h"
#include "adc.h"
unsigned int vol;
void main(void)
{
timer0_Init();//初始化并输出pwm
LCD_Init(); //LCD初始化
LCD_ShowString(1,1,"voltage:");//在屏幕显示“voltage”
while(1)
{
scanf_key(); //键盘扫描
vol=ADC0804_Read(); //读取ad转换值
Disp_vol(vol); //在lcd1602上显示
mdelay(50); //间隔50ms刷新
}
}
pwm部分:(源文件)
#include "pwm.h"
unsigned char times=0;
unsigned char duty_cycle=42;
void timer0_Init(void)
{
TMOD=0x01;//定时器0工作方式1
TH0=0xff;//(65536-10)/256;//赋初值定时
TL0=0x91;//(65536-10)%256;//0.01ms
EA=1;//开总中断
ET0=1;//开定时器0中断
TR0=1;//启动定时器0
}
void tim0() interrupt 1
{
TR0=0;//赋初值时,关闭定时器
TH0=0xff;//(65536-10)/256;//赋初值定时
TL0=0x91;//(65536-10)%256;//0.01ms
TR0=1;//打开定时器
times++;
if(times>=100) //1khz
times=0;
if(times<=duty_cycle) //占空比%,可改
pwm=1;
else pwm=0;
}
(头文件)
#ifndef _PWM_H_
#define _PWM_H_
#include <reg52.h>
sbit pwm=P0^4;
void timer0_Init(void);
#endif
按键部分:(源文件)
#include "key.h"
//1V:6% 2V:13% 3V:20% 4V:27% 5V:35% 6V:42%
//7V:49% 8V:57% 9V:64% 10V:72% 11V:79% 12V:87%
unsigned int percentage[12]={6,13,20,27,35,42,49,57,64,72,79,86};
unsigned int i=5; //初始为6V
extern unsigned char duty_cycle;
void scanf_key()
{
if(i>=11 || i<0) {i=0;}
if(key_up==0 || key_down==0)
{
mdelay(20);
if(key_up==0 || key_down==0)
{
if(key_up==0)
{
while(!key_up);
duty_cycle=percentage[++i];
}
else if(key_down==0)
{
while(!key_down);
duty_cycle=percentage[--i];
}
}
}
}
(头文件)
#ifndef _KEY_H_
#define _KEY_H_
#include <reg52.h>
#include "pwm.h"
#include "delay.h"
sbit key_up=P3^2;
sbit key_down=P3^3;
void scanf_key();
#endif
adc部分:
#include "adc.h"
unsigned int ADC0804_Read(void)
{
unsigned int adtemp=0;
ADC0804_Port = 0xff;
ADC0804_WR = 0;
delay(200);
ADC0804_WR = 1;
delay(1000);
ADC0804_RD = 0;
delay(200);
adtemp=ADC0804_Port*5.88235;
return adtemp;
ADC0804_RD = 1;
}
#ifndef _ADC_H
#define _ADC_H_
#include "delay.h"
#include "lcd1602.h"
//sbit ADC0804_CS = P3^5;//ADC_CS低电平有效
sbit ADC0804_WR = P3^6;//ADC_WR低电平有效
sbit ADC0804_RD = P3^7;//ADC_RD低电平有效
#define ADC0804_Port P1
unsigned int ADC0804_Read(void);//ADC0804读取数据0-255
#endif
delay部分:
#include "delay.h"
void delay(unsigned char x)
{
while(x--);
}
void mdelay(unsigned int ms)
{
unsigned int i;
for(i=0;i<ms;i++)
{
Timer1Init();
}
}
void Timer1Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x66; //设置定时初值
TH1 = 0xFC; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
}
//12MHz调用可延时1ms
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
#ifndef _DELAY_H_
#define _DELAY_H_
#include <reg52.h>
void delay(unsigned char x);
void Timer1Init(void);
void mdelay(unsigned int ms);
void LCD_Delay();
#endif
LCD1602部分:
#include "lcd1602.h"
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
/*显示电压*/
void Disp_vol(unsigned int VolValue)
{
if(VolValue<1000)
{
uchar i;
char NumCode[5];
NumCode[0]=VolValue/100;
NumCode[1]='.'-0x30;
NumCode[2]=VolValue%100/10;
NumCode[3]=VolValue%10;
NumCode[4]='V'-0x30;
for(i=0;i<5;i++)
{
LCD_Disp(0,8+i,0x30+NumCode[i]);
}
}
else
{
uchar i;
char NumCode[6];
NumCode[0]=VolValue/1000;
NumCode[1]=VolValue/100%10;
NumCode[2]='.'-0x30;
NumCode[3]=VolValue%100/10;
NumCode[4]=VolValue%10;
NumCode[5]='V'-0x30;
for(i=0;i<5;i++)
{
LCD_Disp(0,8+i,0x30+NumCode[i]);
}
}
}
//数据显示
void LCD_Disp(uchar i,uchar j,uchar ch)
{
uchar addr;
if(i==0)addr=0x80+j;
else addr=0xc0+j;
LCD_WriteCommand(addr);
LCD_WriteData(ch);
}
#ifndef _LCD1602_H_
#define _LCD1602_H_
#include <reg52.h>
#include "delay.h"
#define uchar unsigned char
//引脚配置:
sbit LCD_RS=P0^5;
sbit LCD_RW=P0^6;
sbit LCD_EN=P0^7;
#define LCD_DataPort P2
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void Disp_vol(unsigned int VolValue);
void LCD_Disp(uchar i,uchar j,uchar ch);
#endif