2018-11-15 13:33:24 qq_40602000 阅读数 2961
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18610 人正在学习 去看看 朱有鹏

数字电压表要求:在AT89C52系统中采用PCF8591芯片,测量0-5V范围内的直流电压,并在2位数码管上显示电压值。

问题咨询请联系-》群名:IT项目交流群    群号:245022761


PROTEUS仿真电路:

 在KEIL中编写的源程序:

#include<reg52.h>    
#include <intrins.h> 

#define  AddWr 0x90    //PCF8591 地址

sbit scl=P2^0;       //I2C  时钟 
sbit sda=P2^1;       //I2C  数据 
bit ack;             //应答标志位

unsigned char date;
sbit C1=P2^6;//数码管1
sbit C2=P2^7;//数码管2
sbit Dp=P2^5;//小数点
table[10]=
{0x3f,0x06,0x5B,0x4F,0x66,
0x6D,0x7D,0x07,0x7F,0x6F};//0~9
unsigned int data dis[3]={0x00,0x00,0x00}; 
unsigned int getData;
/*******************************************************************
                     起动总线函数               
函数原型: 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();          //读取数据0

   Ack_I2c(1);           //发送非应答信号
   Stop_I2c();           //结束总线
   return(dat);
}
/*------------------------------------------------
                 串口初始化函数
------------------------------------------------*/
void init_com(void)
{
 EA=1;        //开总中断
 ES=1;        //允许串口中断
 ET1=1;
 TMOD=0x22;   //定时器T1,在方式2中断产生波特率
 PCON=0x00;   //SMOD=0
 SCON=0x50;   // 方式1 由定时器控制
 TH1=0xfd;    //波特率设置为9600
 TL1=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);
}
/*------------------------------------------------
                    主函数
------------------------------------------------*/
int main()
{  
	while(1)
	{
	 	PCF8591_SendByte(AddWr,0);	 //启动转换
	 	getData=PCF8591_RcvByte(AddWr);  //读转换完的数字信号
	 	dis[1]=getData/51;   //整数位
		dis[2]=getData%51;   //dis[2]位中间暂存数据位
		dis[2]=dis[2]*10;    
		dis[0]=dis[2]/51;    //计算输出电压的小数值	
	C1=1;                		                
	Dp=0;                //打开小数点
	P0=table[dis[0]];    //显示整数部分及小数点
			     
	C1=0; 
	delay(10);    
			
	C2=1;                //打开第二位数码管
	Dp=1;                //关闭小数点
	P0=table[dis[1]];     //显示小数部分
	C2=0;	
	}
}

 

仿真效果:

 

2009-11-11 21:06:00 sdg2008cool 阅读数 874
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18610 人正在学习 去看看 朱有鹏

 

此款电压表主要是利用adc0832作为ad转换芯片,可测范围为0~5v 。lcd16025作为显示芯片。

源程序如下:

#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit rs=P3^0;
sbit rw=P3^1;
sbit e=P3^2;
sbit bf=P0^7;
sbit cs=P1^2;
sbit clk=P1^1;
sbit dio=P1^0;
uchar code table[]="0123456789";
void delay(uint z)
{uint x,y;
for(x=z;x>0;x--)
 for(y=110;y>0;y--);}
bit busytest()
{bit result;
rs=0;
rw=1;
e=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
result=bf;
e=0;
return result;}
void write_date(uchar date)
{while(busytest()==1);
rs=1;
rw=0;
P0=date;
e=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
e=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
e=0;}
void write_com(uchar com)
{while(busytest()==1);
rs=0;
rw=0;
P0=com;
e=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
e=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
e=0;}
void lcd_init()
{delay(15);
write_com(0x38);
delay(5);
write_com(0x38);
delay(5);
write_com(0x38);
delay(5);
write_com(0x01);
delay(5);
write_com(0x06);
delay(5);
write_com(0x0c);
delay(5);}
read_date()
{uchar i,dat;
cs=1;
clk=0;
cs=0;
dio=1;
clk=1;
clk=0;
dio=1;    //选择单通道模式
clk=1;
clk=0;
dio=0;    //选择0通道
clk=1;
clk=0;
dio=1;
clk=1;
for(i=0;i<8;i++)
{clk=1;
clk=0;
dat<<=1;
dat|=dio;}
cs=1;
return dat;}
void display_char()
{write_com(0x00+0x80);
write_date('D');
write_com(0x01+0x80);
write_date('=');
write_com(0x00+0x80+0x40);
write_date('V');
write_com(0x01+0x80+0x40);
write_date('=');
write_com(0x03+0x80+0x40);
write_date('.');
write_com(0x07+0x80+0x40);
write_date('v');}
void display_dv(uchar dv)
{uchar i,j,k;
i=dv/100;
j=dv%100/10;
k=dv%10;
write_com(0x02+0x80);
write_date(table[i]);
write_com(0x03+0x80);
write_date(table[j]);
write_com(0x04+0x80);
write_date(table[k]);}
void display_v(uchar dat)
{uchar i,j,k;
i=dat/51;
j=(dat%51)/10;
k=(dat%51)%10;
write_com(0x02+0x80+0x40);
write_date(table[i]);
write_com(0x04+0x80+0x40);
write_date(table[j]);
write_com(0x05+0x80+0x40);
write_date(table[k]);}
void main()
{uchar temp;
lcd_init();
display_char();
while(1)
{temp=read_date();
display_dv(temp);
display_v(temp);
}}

 

2017-11-10 17:38:34 tq384998430 阅读数 438
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18610 人正在学习 去看看 朱有鹏

开发一个低功耗项目,坑爹的地方不是一个两个。真的是服了。

今天又被万用表坑了一次。系统进入低功耗之后电流在几十个uA左右,这时候使用触摸按键唤醒系统没有问题,可以正常唤醒运行,但是使用指纹模块唤醒的话就会导致掉电,为什么呢???指纹模块耗电量太大???的确指纹模块的耗电量是很大,峰值电流140mA,我就想是不是把系统电源电压拉低了导致单片机复位了,加大的滤波电容行不通,单独使用稳压芯片供电也行不通,使用指纹模块唤醒的话还是会掉电。坑的一笔。

看了下唤醒的过程,指纹模块唤醒后单片机能够正常运行,但是当打开指纹模块的主供电电源的时候出现掉电情况。嗯,还是指纹模块耗电太大了!!!但是为什么单独使用电源供电也不行呢???郁闷之极将串联在电源正极上的万用表拿走了,万用表是在2mA档位。这时候系统尽然不会掉电了。惨的不行。为什么呢?我估计是万用表坑了我。因为在2mA档位下,单片机待机电流只有几十微安,当打开指纹模块之后电流瞬间增加到上百微安,这时候电流表就会采取自我保护功能,断开供电,然后再上电导致了单片机掉电,或者是万用表内部切换了测量档位,切换的瞬间单片机掉电了。

为了验证一下我的说法,我将可恶的万用表继续接到系统电源的正极上去,但是单位切换到200mA档,这时候使用指纹模块唤醒是没有问题得,bingo,基本是我的猜测就是对的了!!!

2020-03-07 11:19:56 weixin_39902512 阅读数 65
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18610 人正在学习 去看看 朱有鹏

硬件调试

一、调试工具
1、直流电源,测试5 - 28V供电;
2、手机充电线,测试USB供电,程序烧录;
3、万用表,测量电压;
4、示波器,测量开关波形,纹波等。

二、焊接样机
焊接好的样机如下图:
在这里插入图片描述

说明:作为硬件工程师,平时要多练焊接,练就一流的焊接技术。样机焊接无误,不存在虚焊、漏焊等,调试时可以节约很多时间,另外,阻容器件数量较多,焊接比较花时间,可以在嘉立创打板时进行贴片,回来再补焊嘉立创不支持贴片的器件。

三、电压测试
开发板支持USB供电;支持直流电源5 - 28V供电;支持USB与直流电源同时供电。
用万用表测量LDO输出电压,3.3V,正常。
用万用表测量开关电源输出电压,3.3V,正常。
1、USB供电,LDO输出电压:
在这里插入图片描述

2、直流电源28V供电,,开关电源输出电压:
在这里插入图片描述

四、开关电源波形测试
1、轻载模式下,开关电源工作在脉冲跳跃模式,开关波形如下图:
在这里插入图片描述

2、在输出部分焊接10Ω电阻,负载电流300mA的开关波形如下:
在这里插入图片描述

五、纹波测试
1、LDO纹波58mV,大约2%。
在这里插入图片描述

进一步降低纹波的方法:加电容滤波,LC滤波等,此处LDO给单片机供电,满足需求。

2、开关电源纹波
轻载下,纹波100mV,大约3%
 在这里插入图片描述
 
330mA负载下,纹波128mV,大约4%
在这里插入图片描述

进一步降低纹波的方法:适当加大输入输出电容,适当增加电感值,输出部分增加二级LC滤波等,此处开关电源给WIFI模块、数码管、接口电路供电等,满足需求。

六、程序烧录测试
1、开发板集成了USB-TTL驱动,如果安装了CH340驱动,插上USB,电脑的设备管理器应该可以显示串口号。
在这里插入图片描述

2、为了方便烧录程序,开发板放置了自锁开关单独控制单片机电源,点击下载后,断开单片机电源,再给单片机通电,即可完成烧录。
3、打开STC-ISP。单片机选择STC15L2K32S2。串口号选择设备管理器显示的串口号,此处为COM11。波特率可以默认或设置的更高;打开程序文件,选择相应的HEX文件;硬件选项的时钟部分选择外部时钟;再点击下载/编程;断电上电即可完成烧录。
在这里插入图片描述

七、教程安排
截止到目前,STC15单片机实战项目的硬件部分已设计完成,接下来进行软件部分的教学。
按照项目需求文档,从点亮第一颗LED灯开始,一步一步实现功能,暂时不录制视频,也不直播,学员动手去实践,我每周会编写软件教学文章,分享在微信公众号,同时,源代码也分享。 学员可以按照教学文章与源代码,快速的学习,掌握。
软件采用状态机、面向对象等编程结构,按产品思维进行编程,方便阅读、移植、维护等。

需要加入硬件家园单片机学习群的朋友,加qq 1273755275。
开源项目,开发工具,技术资料以及更多原创技术文章,请关注微信公众号。
硬件家园 yjjy168168168

作者:刘杰,软硬件技术10年,全职提供技术开发与技术服务、生产支持等。

博文 来自: yu_mi__
没有更多推荐了,返回首页