因为C51只有一组数码管,但是我们需要显示的东西有很多,所以通过按键切换是我们必须要知道的
按键之间有嵌套,切换,计数,对于按键的使用我们是必须知道的
1. HC573锁存器的选择
我们在之前的基础上对其进行了优化,这样就不会出现冲突的问题
因为在使用前,我们直接把所有的给关闭了,当使用的时候先把P0给起来,在引到每个锁存器
/************锁存器选择******************
功能:打通功能需要的锁存器
参数:channel(选择锁存器) dat(一般为oxff 打开通道,但是我们可以去掉这个参数)
***************************************/
void SelectHC573(unsigned channel,unsigned char dat)
{
P0 = dat; //带设置参数数据
switch(channel)
{
case 4:
P2 = (P2 & 0x1f) | 0x80; //Y4,选择LED控制
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; //Y5,选择蜂鸣器和继电器控制
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0; //Y6,选择数码管位置
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0; //Y7,选择数码管段码
break;
case 0:
P2 = (P2 & 0x1f) | 0x00; //在完成后关闭所有锁存器
break;
}
P2 = (P2 & 0x1f) | 0x00; // 修改完成,关闭全部锁存器
}
2. 数码管位置选择与数码管显示
<1> 数码管选择是需要延时函数的。我们是利用余辉效果来进行显示的,所以在数码管显示之后我们需要进行延时,所以我们直接把延时函数放到单个数码管显示之后,这样子显示就变得简单了。
<2>延时延时可以选择 char / int 两种类型,但是需要注意时间,如果时间太长会导致抖动,如果时间过短又会导致数码管变暗。
/****************数码管延时函数**************
功能:对数码管进行延时
参数:t--
*******************************************/
void DelaySMG(unsigned int t)
{
while(t--);
}
/*************数码管显示函数***************
功能: 控制每个数码管的亮暗,在之前的基础上我们使用了延时函数,这样在主体显示就不用添加延时函数了
参数: value (内容) pos(位置)
****************************************/
void DisplaySMG_Bit(unsigned char value, unsigned char pos)
{
SelectHC573(6,0x01<
既然需要控制数码管,我们就需要不同的标志位来进行记录
/***********数码管显示内容选择***********
功能:通过改变flag的参数来选择不同的锁存器
参数:无
***************************************/
void DisplaySMG_Select()
{
switch(SMG_flag)
{
case 1:
(显示时间的函数 DisplayTime);
break;
case 2:
(显示温度的函数 DisplayTemp);
break;
....
}
}
3. 独立按键进行切换
只进行切换当前模式,不能改变当前的状态,所以我们需要在更换模式时,仍然保持数码管的显示,而进行标志位值的改变,当模式多时,我们就需要使用矩阵按键(参考上一篇文章的扫描)
/*****************按键切换**********
功能:通过按键切换模式,也就是我们之前写过的
参数:无
**********************************/
void Key_Scan()
{
if(S4 == 0)
{
Delay(200); //消抖
if(S4 == 0)
{
if(stat_flag == 1) //初始默认的标志位为1——系统时间记录
{
stat_flag =2; //转换模式类型
}
while(S4 == 0)
{
Display_SMGselect(); //按键按下后仍然能显示当前的数码管,这步是需要的
Delay(500);
}
}
}
//模仿上面的操作,进行数码管的操作
else if(S5 == 0)
{
Delay(200);
if(S5 == 0)
{
if(stat_flag == 2)
{
stat_flag =1;
}
while(S5 == 0)
{
Display_SMGselect();
Delay(500);
}
}
}
}
而进行切换的过程中,我们当前状态需要一直进行的,我们就在while循环中执行
4. 系统初始化函数
/*==================系统初始化函数======================
功能:关闭没用的器件,打开需要使用的。进行锁存器的选择
参数:无
=======================================================*/
void InitSystem()
{
SelectHC573(5); //关闭蜂鸣器,继电器
P0 = 0x00;
SelectHC573(4); //打开灯光
P0 = 0xff;
SelectHC573(0); //完成后关闭
}
5. 系统时间函数
我们通过定时器来进行时间计数,通过测试,按键切换不会改变系统运行时间的值,我们不需要记载,他会一直记录着
/*================定时器初始化函数====================
功能: 初始化定时器
参数: 无
=======================================================*/
void InitTimer0()
{
TMOD = 0x21; // 定时器1/2一起赋值
TH0 = (65535 - 50000) / 256; // 0,05s
TL0 = (65535 - 50000) % 256;
ET0 = 1; //使能定时器T0
EA = 1; //使能总中断
TR0 = 1; //启动定时器T0
}
/*===============定时器服务函数===================
功能:利用定时器进行计数
参数:无
=======================================================*/
void ServiceTimer0() interrupt 1
{
TH0 = (65535 - 50000) / 256; //0.05s
TL0 = (65535 - 50000) % 256;
count++;
if(count == 20)
{
count = 0;
t_s++;
}
if(t_s == 60)
{
t_s = 0;
t_m++;
if(t_m == 60)
{
t_m = 0;
t_h++;
}
}
}
6.系统时间函数显示
中断初始化的配置:
<1> 配置工作模式,即对TMOD寄存器编程。
<2> 计算技术初值,即对THx和TLx寄存器进行赋值。
<3> 使能定时/计数器中断,即ET0或ET1置1。
<4> 打开总中断,即EA =1。
<5> 启动定时器,即TR0或TR1置1。
中断服务函数:
<1> 如果不是自动重装模式,需要对THx和TLx重新赋值。
<2> 进行间隔定时到达的逻辑处理(越少越好)
void DisplayTime()
{
//注意的是,如果使用新版的数码管显示函数,就不再需要再延时了
DisPlay_All(0xff); //消隐
DisplaySMG_Bit(SMG_NoDot[t_s%10],7);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[t_s/10],6);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[16],5);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[t_m%10],4);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[t_m/10],3);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[16],2);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[t_h%10],1);
DelaySMG(500);
DisplaySMG_Bit(SMG_NoDot[t_h/10],0);
DelaySMG(500);
DisPlay_All(0xff); //结尾再来一次
}
同时,在老师的视频内容中有说到,在延时的时候需要继续显示一下数码管的内容
void DisplayTmp(unsigned int t)
{
while(t--)
{
DisplayTemp();
}
]
实际测试之后,我们没有在温度显示函数里面再进行延时,也是可以正常显示的
/*********温度读取函数************
功能:进行温度读取(具体在上一篇文章讲过,之后会把内容移动过来)
参数:无
******************************/
void Read_DS18B20_temp()
{
unsigned char LSB,MSB;
init_ds18b20();
Write_DS18B20(0XCC);
Write_DS18B20(0X44);
//Delay_temp(1000);
init_ds18b20();
Write_DS18B20(0XCC);
Write_DS18B20(0Xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
temp = 0x000;
temp = MSB;
temp <<= 8;
temp = temp | LSB;
if((temp & 0xf800) == 0x0000)
{
temp>>=4;
temp = temp *10;
temp = temp +(LSB&0x0f)*0.625;
}
}
需要注意的是,在数码管显示温度之前,我们都要在显示函数前进行温度的读取,也就是把它写在 DisplayTemp 前面
温度显示函数
void DisplayTemp()
{
Read_DS18B20_temp();
DisPlay_All(0xff);
ShowSMG_bit(7,SMGnodot_CA[temp%10]);
DelaySMG(400);
ShowSMG_bit(6,SMGdot_CA[(temp%100)/10]);
DelaySMG(400);
ShowSMG_bit(5,SMGnodot_CA[temp/100]);
DelaySMG(400);
ShowSMG_bit(4,0XFF);
DelaySMG(400);
ShowSMG_bit(3,0XFF);
DelaySMG(400);
ShowSMG_bit(2,0XFF);
DelaySMG(400);
ShowSMG_bit(1,0XFF);
DelaySMG(400);
ShowSMG_bit(0,0XFF);
DelaySMG(400);
DisPlay_All(0xff);
}
DS18B20 温度的底层代码
onewire.c文件
#include "onewire.h"
#include "reg52.h"
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t)
{
while(t--);
}
void Write_DS18B20(unsigned char dat)
{
char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(50);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(50
);
}
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(50);
}
return dat;
}
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(120);
DQ = 0;
Delay_OneWire(800);
DQ = 1;
Delay_OneWire(100);
initflag = DQ;
Delay_OneWire(50);
return initflag;
}
onewire.h文件
我们之后也可以把前面写的函数给封装到文件里
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
unsigned char rd_temperature(void);
bit init_ds18b20(void);
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
#endif
DS1302有关日历和时钟的寄存器有12个,我们最常用的有7个。
什么是BCD码?
就是用十六进制来表示十进制。什么意思?怎么理解?
例如,十六进制数0x13的值为整数19,但BCD码表示的是整数13。
DS1302将地址和读写控制放到一个字节里面,形成一个控制字,格式如下:
我们往DS1304里面写入一个8为的数据(指令),把它分为上面8个
通过上面的控制字格式,大家就可以明白为什么DS1302读寄存器和写寄存器的地址是不一样的了,因为这个地址包含了读写控制位。为了方便程序设计,我们把
读寄存器地址、写寄存器地址和日历时钟寄存器方面用三个数组定义。
BCD码,用16进制来表示10进制
0x30(秒) 0x50(50分) 如上图所示,依次类推
底层驱动代码实现可参考如下:
DS1302.c
unsigned char DS1302_ReadByte(unsigned char addr)
{
unsigned char n,dat,tmp;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for(n=0; n<8; n++) //发送要读出数据的内存地址
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
for(n=0; n<8; n++) //读出该地址内存的数据
{
tmp = DSIO;
dat = (dat>>1) | (tmp<<7);
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;
_nop_();
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
unsigned char n;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for (n=0; n<8; n++) //发送要写入数据的内存地址
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++) //将指定内容写入该地址的内存
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;
_nop_();
}
有了上面两个SPI底层代码,我们读出DS1302的数据就变得非常简单了
我们可以参考下面的源码:
#include "reg52.h"
#include "intrins.h"
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7;
sbit SCLK = P1^7;
sbit RST = P1^3;
sbit DSIO = P2^3;
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
unsigned char TIME[7] = {0x30, 0x50, 0x23, 0x17, 0x02, 0x06, 0x18};
unsigned char code SMG_NoDot[18] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f};
void DelaySMG(unsigned int time)
{
while(time--);
}
void Init74HC138(unsigned char n)
{
switch(n)
{
case 4:
HC138_A = 0;
HC138_B = 0;
HC138_C = 1;
break;
case 5:
HC138_A = 1;
HC138_B = 0;
HC138_C = 1;
break;
case 6:
HC138_A = 0;
HC138_B = 1;
HC138_C = 1;
break;
case 7:
HC138_A = 1;
HC138_B = 1;
HC138_C = 1;
break;
case 8:
HC138_A = 0;
HC138_B = 0;
HC138_C = 0;
break;
}
}
void DispaySMG_Bit(unsigned char value, unsigned char pos)
{
Init74HC138(6);
P0 = (0x01 << pos);
Init74HC138(7);
P0 = value;
}
void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
unsigned char n;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for (n=0; n<8; n++)
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++)
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;
_nop_();
}
unsigned char DS1302_ReadByte(unsigned char addr)
{
unsigned char n,dat,tmp;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for(n=0; n<8; n++)
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
for(n=0; n<8; n++)
{
tmp = DSIO;
dat = (dat>>1) | (tmp<<7);
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;
_nop_();
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
//DS1302的初始化
void DS1302_Config()
{
unsigned char n;
DS1302_WriteByte(0x8E,0x00); //写入保护
for (n=0; n<7; n++)
{
//写入时分秒年月日
DS1302_WriteByte(WRITE_RTC_ADDR[n],TIME[n]);
}
DS1302_WriteByte(0x8E,0x80);
}
//DS1302读取当前时间
void DS1302_ReadTime()
{
unsigned char n;
for (n=0; n<7; n++)
{
//读取的内存地址,读7个时分秒年月日
TIME[n] = DS1302_ReadByte(READ_RTC_ADDR[n]);
}
}
//数码管显示年月日
void XMF_ShowRealTime()
{
//小时
DispaySMG_Bit(SMG_NoDot[TIME[2]/16],0);
DelaySMG(500);
DispaySMG_Bit(0xff,0);
DispaySMG_Bit(SMG_NoDot[TIME[2]&0x0f],1);
DelaySMG(500);
DispaySMG_Bit(0xff,1);
DispaySMG_Bit(SMG_NoDot[16],2);
DelaySMG(500);
DispaySMG_Bit(0xff,2);
//分钟
DispaySMG_Bit(SMG_NoDot[TIME[1]/16],3);
DelaySMG(500);
DispaySMG_Bit(0xff,3);
DispaySMG_Bit(SMG_NoDot[TIME[1]&0x0f],4);
DelaySMG(500);
DispaySMG_Bit(0xff,4);
DispaySMG_Bit(SMG_NoDot[16],5);
DelaySMG(500);
DispaySMG_Bit(0xff,5);
//秒
DispaySMG_Bit(SMG_NoDot[TIME[0]/16],6);
DelaySMG(500);
DispaySMG_Bit(0xff,6); //消隐
DispaySMG_Bit(SMG_NoDot[TIME[0]&0x0f],7); //&0x0f可以改为 %16
DelaySMG(500);
//关闭全部数码管,不关闭会导致亮度可能不同
DispaySMG_Bit(0xff,7);
}
void main()
{
DS1302_Config(); //DS1302初始化
while(1)
{
// 显示前需要先读取1302的数据
DS1302_ReadTime();
XMF_ShowRealTime();
}
}
9- 串口中断
TH1和TL1:设置波特率参数。
TMOD:设置定时器1的工作模式。
SBUF:串行通信数据的发送和接收缓冲器。
SCON:串行接口控制寄存器。
TR1: 定时器
ES: 串口中断
EA: 总中断
/*=================串口初始化函数========================
功能:将串口设置为模式1,波特率9600,允许接收
参数
=======================================================*/
void InitUart()
{
TMOD = 0x21; //T0与T1一起赋值
TH1 = 0xfd; //设置9600波特率
TL1 = 0xfd;
TR1 = 1; // 启动定时器1
SCON = 0x50; //8位UART
AUXR = 0x00; //辅助寄存器
ES = 1; //使能串口中断
EA = 1; //使能总中断
}
/*=================串口中断服务函数====================
功能:接收上位机所发送的字符
=======================================================*/
void ServiceUart() interrupt 4
{
if(RI == 1)
{
command = SBUF; //½«½ÓÊÕµ½µÄÊý¾Ý±£´æµ½command±äÁ¿
RI = 0; //½«½ÓÊÕÍê³É±êÖ¾RIÇå0
}
}
/*=================串口服务函数====================
功能:接收上位机发送的数据并保持在command里
参数:无
=======================================================*/
void SendByte(unsigned char dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
void SendString(unsigned char *str)
{
while(*str != '\0')
{
SendByte(*str++);
}
}
/*===============串口信息接收执行函数==================
功能:接收上位机消息,进行灯光控制
参数:无
=======================================================*/
void ExecuteCommand()
{
if(command != 0x00) //接收的消息不为空
{
switch(command & 0xf0) //将命令类型取出
{
case 0xa0: //远程控制灯光
SelectHC573(4);
stat_led = (stat_led | 0x0f) & (~command | 0xf0);
P0 = stat_led;
SelectHC573(0);
command = 0x00;
break;
case 0xb0: //读取系统运行时间
SendByte((t_h / 10 << 4) | (t_h % 10));
SendByte((t_m / 10 << 4) | (t_m % 10));
SendByte((t_s / 10 << 4) | (t_s % 10));
command = 0x00;
break;
}
}
}
10-AD-DA
(参考江科大自化协)
AD: 模-数转化~ DA:数-模转化
现象:根据可调电阻,可以改变LCD(在我们使用的板子中改变的为数码管的数字),电压的大小。
· AD转换通常有多个输入通道,多个开关连接至AD转换
· AD/DA与单片机数据传输可使用并口,也可以使用串口
· 可将AD/DA模块集成在单片机内,这样直接写入就可以AD/DA转换,单片机的IO口可直接复写为AD/DA的通道。
试题: 配置要求
内部振荡器频率设置为 12mhz
键盘工作模式跳线J15配置为BTN独立按键模式
扩展方式跳线J13配置为IO模式
· 显示功能
(1)频率显示界面
(2)电压显示界面
· 按键功能
(1) S4:定义为显示界面切换
(2) S5:定义为DAC输出模式切换
(3) S6:LED功能控制按键
(4) S7:数码管功能控制
/****************ÒýÈëÍ·ÎļþÓ붨Òå±äÁ¿************
±à³Ìģʽ:I/Oģʽ
************************************************/
#include "reg52.h"
#include "iic.h"
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
//-----¹²ÑôÊýÂë¹ÜµÄ¶ÎÂë±àÂë±í£¨ÎÞСÊýµã£©----
unsigned char code SMG_DM_NoDot[19]={0xc0,0xf9,
0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0xc1};
// Êý×Ö0. ~ 9.
unsigned char code SMG_DM_dot[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
unsigned int count_f = 0; //NE555ÐźÅƵÂʼÆÊý
unsigned char count_t = 0; //¶¨Ê±Æ÷ÖжϼÆÊý
unsigned int dat_f = 0; //²âÁ¿ÆµÂÊÊýÖµ
unsigned int dat_v = 0; //²âÁ¿µçѹÊýÖµ
unsigned char dat_rb2 = 0; //µçѹ²ÉÑùÊýÖµ
bit F_DIS=0; // ƵÂʺ͵çѹÏÔʾÇл»±êÖ¾
bit F_VOL=0; // DACµçѹÊä³öÇл»
bit F_SMG=0; // ÊýÂë¹ÜÏÔʾÇл»
bit F_LED=0; // LEDÇл»
bit F_DAC=0; // ADC²ÉÑùºÍDACÊä³öÇл»
/****************ÑÓʱº¯ÊýºÍËø´æÆ÷Ñ¡Ôñº¯Êý************
************************************************/
// ÊýÂë¹ÜÑÓʱº¯Êý
void DelaySMG(unsigned int t)
{
while(t--);
}
// Ëø´æÆ÷Ñ¡Ôñº¯Êý
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0:
P2 = (P2 & 0X1F) | 0X00;
break;
}
}
/**************ÊýÂë¹Üµ×²ãÇý¶¯º¯Êý***********
********************************************/
// È«¿ØÖÆÊýÂë¹Ü£¬ÓÃÓÚÿ¸öÏÔʾǰºó
void DisPlaySMG_All(unsigned char value)
{
SelectHC573(6); //?????
P0 = 0xff;
SelectHC573(7);
P0 = value;
}
// ÊýÂë¹ÜÏÔʾº¯Êý
void DisplaySMG_Bit(unsigned char pos,unsigned char value)
{
P0 = 0xff; // ÏûÒþ
SelectHC573(6); // λÖÃ
P0 = 0x01 << pos ;
SelectHC573(7); // Êý×Ö
P0 = value;
}
/********ADC²ÉÑùº¯ÊýºÍDACÊä³öº¯Êý***********
********************************************/
//ADC²ÉÑùº¯Êý
void ReadData_ADC()
{
IIC_Start();
IIC_SendByte(0x90); //É豸дÈëµØÖ·
IIC_WaitAck();
IIC_SendByte(0x43); //ADCÉèÖà £¡£¡£¡£¡£¡£¡
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91); //É豸дÈëµØÖ·
IIC_WaitAck();
dat_rb2 = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
dat_v = dat_rb2*2; // ¼ÆËãʵ¼Êµçѹ
}
// DACÊä³öÆ÷º¯Êý
void SetData_DAC(unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90); //É豸дÈëµØÖ·
IIC_WaitAck();
IIC_SendByte(0x40); //ADCÉèÖà £¡£¡£¡£¡£¡£¡
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
/********¶¨Ê±Æ÷³õʼ»¯º¯Êý*********/
void InitTimerX()
{
//¶¨Ê±Æ÷0¼ÆÊý£¬Ä£Ê½2£»¶¨Ê±Æ÷1¶¨Ê±,ģʽ1 TMOD
TH0 = 0XFF;
TL0 = 0XFF;
TH1 =(65535 - 50000) / 256; //¶¨Ê±0.05S
TL1 =(65535 - 50000) % 256;
TMOD = 0X16;
ET0 = 1; //ʹÄܶ¨Ê±Æ÷T0
ET1 = 1; //ʹÄܶ¨Ê±Æ÷T1
EA = 1; //ʹÄÜÖжÏ
TR0 = 1; //Æô¶¯¶¨Ê±Æ÷0
TR1 = 1; //Æô¶¯¶¨Ê±Æ÷1
}
// ¶¨Ê±Æ÷ÖжϷþÎñº¯Êý
void Service_Timer0() interrupt 1
{
count_f++; //ÀÛ¼ÆNE555Ä£¿éÊä³öÐźŸöÊý
}
void Service_Timer1() interrupt 3
{
count_t++;
if(count_f % 5 == 0) //ÿ0,5sË¢ÐÂÒ»´ÎADCµçѹÊý¾Ý
{
F_DAC = ~F_DAC;
}
if(count_t == 20) //ÿ1sË¢ÐÂÒ»´ÎƵÂÊÊý¾Ý
{
dat_f = count_f;
count_f = 0;
count_t = 0;
}
}
/*********µçѹÊý¾ÝÓëƵÂÊÊý¾ÝÏÔʾº¯Êý*********/
// µçѹÏÔʾº¯Êý
void DisplaySMG_V()
{
DisPlaySMG_All(0xff);
DisplaySMG_Bit(0,SMG_DM_NoDot[18]);
DelaySMG(500);
DisplaySMG_Bit(5,SMG_DM_dot[(dat_v / 100) % 10]);
DelaySMG(500);
DisplaySMG_Bit(6,SMG_DM_NoDot[(dat_v / 10) % 10]);
DelaySMG(500);
DisplaySMG_Bit(7,SMG_DM_NoDot[dat_v % 10]);
DelaySMG(500);
DisPlaySMG_All(0xff);
}
// ƵÂÊÏÔʾº¯Êý
void DisplaySMG_F()
{
DisPlaySMG_All(0xff);
DisplaySMG_Bit(0,SMG_DM_NoDot[15]);
if(dat_f > 9999)
DisplaySMG_Bit(3,SMG_DM_NoDot[dat_f / 10000]);
if(dat_f > 999)
DisplaySMG_Bit(4,SMG_DM_NoDot[(dat_f / 1000) % 10]);
if(dat_f > 99)
DisplaySMG_Bit(5,SMG_DM_NoDot[(dat_f / 100) % 10]);
if(dat_f > 9)
DisplaySMG_Bit(6,SMG_DM_NoDot[(dat_f / 10) % 10]);
DisplaySMG_Bit(7,SMG_DM_NoDot[dat_f % 10]);
DisPlaySMG_All(0xff);
}
/*********µçѹÓëƵÂʵÄ״ָ̬ʾ*********/
// ÔÝʱֹͣ£¬ÏȲ»Ê¹Óã¬ÏÈֻʹÓÃÊýÂë¹Ü
//ÊýÂë¹ÜÏÔʾº¯Êý
void Display()
{
if(F_SMG == 0)
{
if(F_DIS == 0)
DisplaySMG_V();
else
DisplaySMG_F();
}
else //ÊýÂë¹Ü¹Ø±Õ
{
SelectHC573(6);
P0 = 0xff;
SelectHC573(7);
P0 = 0xff;
}
SelectHC573(0);
}
// °´¼üɨÃ躯Êý
void Scan_Keys()
{
if(S4 == 0)
{
DelaySMG(100); //֮ǰÎÒÃÇҲ˵¹ý£¬°´¼üÇл»ÊÇÒ»¸ö£¬µ«ÊÇ·ÖÌõ¼þµÄÏÔʾҪµ¥¶Àд³öÀ´£¬²»¹ÜÄÄÖÖÇé¿ö¶¼ÒªÒ»Ö±ÏÔʾ
F_DIS = ~F_DIS;
while(S4 == 0)
Display();
}
if(S5 == 0)
{
DelaySMG(100); //֮ǰÎÒÃÇҲ˵¹ý£¬°´¼üÇл»ÊÇÒ»¸ö£¬µ«ÊÇ·ÖÌõ¼þµÄÏÔʾҪµ¥¶Àд³öÀ´£¬²»¹ÜÄÄÖÖÇé¿ö¶¼ÒªÒ»Ö±ÏÔʾ
F_VOL = ~F_VOL;
while(S5 == 0)
Display();
}
if(S7 == 0)
{
DelaySMG(100); //֮ǰÎÒÃÇҲ˵¹ý£¬°´¼üÇл»ÊÇÒ»¸ö£¬µ«ÊÇ·ÖÌõ¼þµÄÏÔʾҪµ¥¶Àд³öÀ´£¬²»¹ÜÄÄÖÖÇé¿ö¶¼ÒªÒ»Ö±ÏÔʾ
F_SMG = ~F_SMG;
while(S7 == 0)
Display();
}
}
// ³õʼ»¯º¯Êý
void InitSystem()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(4);
P0 = 0xff;
SelectHC573(0);
InitTimerX();
}
void main()
{
InitSystem();
while(1)
{
Scan_Keys();
if(F_DAC == 0)
{
ReadData_ADC();
}
else
{
if(F_VOL == 0)
{
SetData_DAC(102); //Êä³ö2vµçѹ
}
else
{
SetData_DAC(dat_rb2);
}
}
Display();
}
}
· 在NE555内部。有3个5k电阻分压
· 基本原理:
低电平触发端TRIG和高电平THR:
两者电压均小于各自的参考电压,U0 = 1,放电管截至
两者电压均大于于各自的参考电压,U0 = 0,放电管导通
` NE555是一个纯硬件设计。其功能已经确定了,在这个板子上,555相当于一个信号发生电路。通过Rb3可改变输出信号频率
#include "reg52.h"
#include "absscc.h"
unsigned int count_f = 0;
unsigned int dat_f = 0;
unsigned char count_t = 0;
void Init_Timer()
{
//¶¨Ê±Æ÷0ÓÃ×÷¼ÆÊý£¬8λÖØ×°·½Ê½
TH0 = 0xff;
TL0 = 0xff;
//¶¨Ê±Æ÷1ÓÃ×÷¶¨Ê±£¬¶¨Ê±Îª0.05s
TH1 = (65535 - 50000) / 256;
TL1 = (65535 - 50000) % 256;
TMOD = 0x16;
ET0 = 1;
ET1 = 1;
EA = 1;
TR0 = 1;
TR1 = 1;
}
void Service_T0() interrupt 1
{
count_f++;
}
void Service_T1() interrupt 3
{
TH1 = (65535 - 50000) / 256;
TL1 = (65535 - 50000) % 256;
count_t++;
if(count_t == 20)
{
dat_f = count_f;
count_f = 0;
count_t = 0;
}
}
在上面的试题中我们有数码管显示函数,在这里我们就只体现了555的计数功能