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);
	}
	
}
  • 25
    点赞
  • 206
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
很高兴为您提供帮助。以下是一个示例程序,请注意修改引脚号和其他参数以适应您自己的硬件。 ```c #include <reg51.h> // 定义管脚 sbit rs=P2^0; sbit rw=P2^1; sbit en=P2^2; // 函数声明 void lcd_delay(unsigned int z); void lcd_wcmd(unsigned char cmd); void lcd_wdata(unsigned char dat); void init_adc(); unsigned int read_adc(unsigned char ch); void init_lcd(); void display(unsigned char addr, unsigned char *str); // 主函数 void main() { unsigned int light, soil; char buf[16]; init_adc(); init_lcd(); while (1) { light = read_adc(0); soil = read_adc(1); // 显示光强度 lcd_wcmd(0x80); // 移动指针到第一行第一列 sprintf(buf, "Light: %04d", light); // 将数据格式化为字符串 display(0x80, buf); // 显示字符串到 LCD // 显示土壤湿度 lcd_wcmd(0xc0); // 移动指针到第二行第一列 sprintf(buf, "Soil : %04d", soil); // 将数据格式化为字符串 display(0xc0, buf); // 显示字符串到 LCD } } // 初始化 ADC void init_adc() { P1 = 0xff; // 设置所有管脚为输入 } // 读取 ADC unsigned int read_adc(unsigned char ch) { unsigned int result; // 选择信道 P1 &= 0xf0; P1 |= (ch & 0x0f); // 开始转换 ADC_CONTR = 0x90; // 等待转换完成 while (!(ADC_CONTR & 0x20)); // 读取结果 result = ADC_RES; result <<= 8; result |= ADC_RESL; return result; } // 初始化 LCD void init_lcd() { // 设置管脚为输出 P0 = 0; rs = 0; rw = 0; en = 0; // 等待 LCD 上电 lcd_delay(15000); // 执行初始化命令 lcd_wcmd(0x38); // 设置数据格式:16 位、5x7 点阵、双行显示 lcd_wcmd(0x0c); // 打开显示,关闭光标、光标闪烁 lcd_wcmd(0x06); // 设置文字不动,地址自增 lcd_wcmd(0x01); // 清屏 } // 发送命令到 LCD void lcd_wcmd(unsigned char cmd) { rs = 0; rw = 0; P0 = cmd; en = 1; lcd_delay(1000); en = 0; } // 发送数据LCD void lcd_wdata(unsigned char dat) { rs = 1; rw = 0; P0 = dat; en = 1; lcd_delay(1000); en = 0; } // 延时函数 void lcd_delay(unsigned int z) { unsigned int x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } // 在 LCD显示字符串 void display(unsigned char addr, unsigned char *str) { lcd_wcmd(addr); while (*str != '\0') { lcd_wdata(*str++); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值