本文主要是介绍【C51单片机】制作数字电压表(仿真),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、功能描述
数字电压表:在AT89C52系统中采用PCF8591芯片,测量0-5V范围内的直流电压,并在2位数码管上显示电压值。
2、使用PROTEUS元件
PCF8591数模转换 二位数码管 排阻
3、PROTEUS中设计的电路图
4、源代码
#include<reg52.h> //包含单片机寄存器的头文件
#include <intrins.h> #define AddWr 0x90 //PCF8591 地址// 变量定义
unsigned char AD_CHANNEL=0;
unsigned char D[32];
unsigned char code table[10]={0xC0,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //共阳极数码管0~9显示的数值表
unsigned int data dis[3]={0x00,0x00,0x00}; //用以计算存储输出电压的3元素数组sbit scl=P2^0; //I2C 时钟
sbit sda=P2^1; //I2C 数据
bit ack; /*应答标志位*/
sbit C1=P2^6;//数码管位选
sbit C2=P2^7;//数码管位选
sbit Dp=P2^5;//小数点unsigned char date;/*******************************************************************起动总线函数
函数原型: void Start_I2c();
功能: 启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{sda=1; /*发送起始条件的数据信号*/_nop_();scl=1;_nop_(); /*起始条件建立时间大于4.7us,延时*/_nop_();_nop_();_nop_();_nop_(); sda=0; /*发送起始信号*/_nop_(); /* 起始条件锁定时间大于4μs*/_nop_();_nop_();_nop_();_nop_(); scl=0; /*钳住I2C总线,准备发送或接收数据 */_nop_();_nop_();
}/*******************************************************************结束总线函数
函数原型: void Stop_I2c();
功能: 结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop_I2c()
{sda=0; /*发送结束条件的数据信号*/_nop_(); /*发送结束条件的时钟信号*/scl=1; /*结束条件建立时间大于4μs*/_nop_();_nop_();_nop_();_nop_();_nop_();sda=1; /*发送I2C总线结束信号*/_nop_();_nop_();_nop_();_nop_();
}/*******************************************************************字节数据发送函数
函数原型: void I2C_SendByte(UCHAR c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0) 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void I2C_SendByte(unsigned char c)
{unsigned char i;for(i=0;i<8;i++) /*要传送的数据长度为8位*/{if((c<<i)&0x80)sda=1; /*判断发送位*/else sda=0; _nop_();scl=1; /*置时钟线为高,通知被控器开始接收数据位*/_nop_(); _nop_(); /*保证时钟高电平周期大于4μs*/_nop_();_nop_();_nop_(); scl=0; }_nop_();_nop_();sda=1; /*8位发送完后释放数据线,准备接收应答位*/_nop_();_nop_(); scl=1;_nop_();_nop_();_nop_();if(sda==1)ack=0; else ack=1; /*判断是否接收到应答信号*/scl=0;_nop_();_nop_();
}/*******************************************************************字节数据接收函数
函数原型: UCHAR I2C_RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数应答从机。
********************************************************************/
unsigned char I2C_RcvByte()
{unsigned char retc=0,i; sda=1; /*置数据线为输入方式*/for(i=0;i<8;i++){_nop_(); scl=0; /*置时钟线为低,准备接收数据位*/_nop_();_nop_(); /*时钟低电平周期大于4.7μs*/_nop_();_nop_();_nop_();scl=1; /*置时钟线为高使数据线上数据有效*/_nop_();_nop_();retc=retc<<1;if(sda==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */_nop_();_nop_(); }scl=0; _nop_();_nop_();return(retc);
}/********************************************************************应答子函数
函数原型: void Ack_I2c(bit a);
功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack_I2c(bit a)
{ if(a==0)sda=0; /*在此发出应答或非应答信号 */else sda=1; /*0为发出应答,1为非应答信号 */_nop_();_nop_();_nop_(); scl=1;_nop_();_nop_(); /*时钟低电平周期大于4μs*/_nop_();_nop_();_nop_(); scl=0; /*清时钟线,住I2C总线以便继续接收*/_nop_();_nop_();
}/************************************************************
* 函数名 : Pcf8591_DaConversion
* 函数功能 : PCF8591的输出端输出模拟量
* 输入 : addr(器件地址),channel(转换通道),value(转换的数值)
* 输出 : 无
******************* *****************************************/
bit Pcf8591_DaConversion(unsigned char addr,unsigned char channel, unsigned char Val)
{Start_I2c(); //启动总线I2C_SendByte(addr); //发送器件地址if(ack==0)return(0);I2C_SendByte(0x40|channel); //发送控制字节if(ack==0)return(0);I2C_SendByte(Val); //发送DAC的数值 if(ack==0)return(0);Stop_I2c(); //结束总线return(1);
}/************************************************************
* 函数名 : Pcf8591_SendByte
* 函数功能 : 写入一个控制命令
* 输入 : addr(器件地址),channel(转换通道)
* 输出 : 无
************************************************************/
bit PCF8591_SendByte(unsigned char addr,unsigned char channel)
{Start_I2c(); //启动总线I2C_SendByte(addr); //发送器件地址if(ack==0)return(0);I2C_SendByte(0x40|channel); //发送控制字节if(ack==0)return(0);Stop_I2c(); //结束总线return(1);
}/************************************************************
* 函数名 : PCF8591_RcvByte
* 函数功能 : 读取一个转换值
* 输入 :
* 输出 : dat
************************************************************/
unsigned char PCF8591_RcvByte(unsigned char addr)
{ unsigned char dat;Start_I2c(); //启动总线I2C_SendByte(addr+1); //发送器件地址if(ack==0)return(0);dat=I2C_RcvByte(); //读取数据0Ack_I2c(1); //发送非应答信号Stop_I2c(); //结束总线return(dat);
}
/*------------------------------------------------串口初始化函数
------------------------------------------------*/
void init_com(void)
{EA=1; //开总中断ES=1; //允许串口中断ET1=1; //允许定时器T1的中断TMOD=0x20; //定时器T1,在方式2中断产生波特率PCON=0x00; //SMOD=0SCON=0x50; // 方式1 由定时器控制TH1=0xfd; //波特率设置为9600TL1=0xfd;TR1=1; //开定时器T1运行控制位}
/*------------------------------------------------延时函数
------------------------------------------------*/
void delay(unsigned char i)
{unsigned char j,k; for(j=i;j>0;j--)for(k=125;k>0;k--);
}
/*------------------------------------------------
把读取值转换成一个一个的字符,给串口显示
------------------------------------------------*/
void To_ascii(unsigned char num)
{ SBUF=num/100+'0'; delay(200); SBUF=num/10%10+'0'; delay(200); SBUF=num%10+'0';delay(200);
}
/*------------------------------------------------主函数
------------------------------------------------*/
main()
{ init_com();while(1){/********以下AD-DA处理*************/ PCF8591_SendByte(AddWr,0); //启动转换D[0]=PCF8591_RcvByte(AddWr); //读转换完的数字信号,ADC0 模数转换1 光敏电阻 /********以下将AD的值通过串口发送出去*************/dis[1]=D[0]/51; //每刻度值为5/256V,所以电压值为输出的8位数字值*5/256V,计算输出电压的整数值dis[2]=D[0]%51; //dis[2]位中间暂存数据位dis[2]=dis[2]*10; dis[0]=dis[2]/51; //计算输出电压的小数值 C1=0; //关闭第二位数码管C2=1; //打开第一位数码管Dp=1; //打开小数点P1=table[dis[0]]; //显示整数部分及小数点delay(10); //延时一定时间C2=0; //关闭第一位数码管C1=1; //打开第二位数码管Dp=0; //关闭小数点P1=table[dis[1]]; //显示小数部分}
}
5、实验效果
电路图下载链接为:https://download.csdn.net/download/qq_42449351/12610850
由于不能上传视频,所以我将效果视频上传至优酷,请点击观看------->效果视频展示
问题咨询及项目源码请加群:
QQ群
名称:IT项目交流群
群号:245022761
这篇关于【C51单片机】制作数字电压表(仿真)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!