/*----------------------------------------------------------------------------
=======================================
JD51 2015开发板配套实验学习例程
=======================================
************************************程序功能说明******************************
本程序用来检测JD51开发板程序运行及部分硬件功能是否正常;
实现功能流程:
1)开发板上电,依次进行LED,LCD,数码管自检,而后蜂鸣器响四声,自检完毕;
2)按键2:播放“生日快乐”音乐;
3)按键3:温度传感器测试 温度高于31度时,蜂鸣器报警;
4)按键4:红外控制LED点灯。(注:红外模块对应NEC系列遥控器)
*****************************************************************************/
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
extern void infrared(void);
sbit E=P2^7; //1602使能引脚
sbit RW=P3^6; //1602读写引脚
sbit RS=P2^6; //1602数据/命令选择引脚
sbit DQ =P3^7; //DS18B20接P3^7口
sbit CE573=P2^5;
sbit BUZZER=P2^4;
sbit KEY1=P3^2;
sbit KEY2=P3^3;
sbit KEY3=P3^4;
sbit KEY4=P3^5;
sbit KEY5=P3^7;
sbit P2_3=P2^3;
code unsigned char digseg[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
// 0 1 2 3 4 5 6 7 8 9 A b C d E F
code unsigned char segsel[]={0xfe,0xfd,0xfb,0xf7};
//数码管段选
uchar code table[]={0xc0,0xf9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90};
//四位8段数码管共阳0——9
uchar code table1[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
//四位8段数码管带小数点共阳0——9
uchar m;
uint x;
uchar IRtime; //检测红外高电平持续时间(脉宽)
uchar IRcord[4]; //此数组用于储存分离出来的4个字节的数据(用户码2个字节+键值码2个字节)
uchar IRdata[33]; //此数组用于储存红外的33位数据(第一位为引导码用户码16+键值码16)
bit IRpro_ok,IRok; //第一个用于红外接收4个字节完毕。IRok用为检测脉宽完毕
void _delay(uchar ms) // 延时子程序
{
uchar i ;
while(ms--)
{
for(i = 0 ; i<250;i++) ;
}
}
void init() //初始化定时器0 和外部中断0
{
TMOD=0x22; //定时器0和定时器1工作方式2,8为自动重装
TH0=0x00; //高8位装入0那么定时器溢出一次的时间是256个机器周期
TL0=0x00;
EA=1; //总中断
ET0=1; //定时器0中断
TR0=1; //启动定时器0
IT0=1; //设置外部中断0为跳沿出发方式,来一个下降沿触发一次
EX0=1; //启动外部中断0
// TH1=0xfd; //此溢出率为波特率9600
// TL1=0xfd;
TR1=1; //启动定时器1
SM1=1; //设置串口工作方式1,10位异步收发器
// REN=1; //允许串口接受位
// ES=1; //开串口中断
}
void time0() interrupt 1 //定义定时器0
{
IRtime++; //检测脉宽,1次为278us
}
void int0() interrupt 0 //定义外部中断0
{
static uchar i; // 声明静态变量(在跳出函数后在回来执行的时候不会丢失数值)i用于把33次高电平的持续时间存入IRdata
static bit startflag; //开始储存脉宽标志位
if(startflag) //开始接收脉宽检测
{
if((IRtime<53)&&(IRtime>=32)) /*判断是否是引导码,底电平9000us+高4500us
这个自己可以算我以11.0592来算了NEC协议的引导码底8000-100000+高4000-5000
如果已经接收了引导码那么i不会被置0就会开始依次存入脉宽*/
i=0; //如果是引导码那么执行i=0把他存到IRdata的第一个位
IRdata[i]=IRtime; //以T0的溢出次数来计算脉宽,把这个时间存到数组里面到后面判断
IRtime=0; //计数清零,下一个下降沿的时候在存入脉宽
i++; //计数脉宽存入的次数
if(i==33) //如果存入33次
{
IRok=1; //那么表示脉宽检测完毕
i=0; //把脉宽计数清零准备下次存入
}
}
else
{
IRtime=0; //引导码开始进入把脉宽计数清零开始计数
startflag=1; //开始处理标志位置1
}
}
void display1()
{
P0=table[m];
P2_3 = 0;
_delay(5);
P2_3 = 1;
}
void IRcordpro() //提取它的33次脉宽进行数据解码
{
uchar i,j,k,cord,value; /*i用于处理4个字节,j用于处理每一位,k用于代表哪一位脉宽
cord用于取出脉宽的时间判断是否符合1的脉宽时间*/
k=1; //从第一位脉宽开始取,丢弃引导码脉宽
for(i=0;i<4;i++)
{
for(j=0;j<8;j++)
{
cord=IRdata[k]; //把脉宽存入cord
if(cord>5) //如果脉宽大于我11.0592的t0溢出率为约278us*7=1668那么判断为1
value=value|0x80; /*接收的时候是先接收最低位,
把最低位先放到value的最高位在和0x08按位或一下
这样不会改变valua的其他位的数值只会让他最高位为1*/
if(j<7)
{
value=value>>1; //value位左移依次接收8位数据。
}
k++; //每执行一次脉宽位加1
}
IRcord[i]=value; //每处理完一个字节把它放入IRcord数组中。
value=0; //清零value方便下次在存入数据
}
IRpro_ok=1; //接收玩4个字节后IRpro ok置1表示红外解码完成
}
void infrared()
{
// uchar i;
init(); //执行初始化定时器0和外部中断0
while(1) //大循环
{
if(IRok) //判断脉宽是否检测完毕
{
IRcordpro();//根据脉宽解码出4个字节的数据
IRok=0; //重新等待脉宽检测
if(IRpro_ok) //判断是否解码完毕
{
switch(IRcord[2])//判断第三个数码值
{
case 0x16:m=0;break;
case 0x0c:m=1;break;
case 0x18:m=2;break;
case 0x5e:m=3;break;
case 0x08:m=4;break;
case 0x1c:m=5;break;
case 0x5a:m=6;break;
case 0x42:m=7;break;
case 0x52:m=8;break;
case 0x4a:m=9;break;
default :break;
}
IRpro_ok=0;
}
}
//for(i=100;i>0;i--)
//{
display1();
// }
}
}
//串口、中断、初始化设置子函数
//11.0592MH晶振下,波特率9600,无奇偶校验
/*void initmpu(void)
{
//定时器1的工作方式2
TMOD=0x20;
//装载计数初值
TL1=0xfd;
TH1=0xfd;
//采用串口工作方式1,无奇偶校验
SCON=0x50;
//串口波特率不加倍
PCON=0x00;
//开总中断,开串口中断
TR1=1;
IE=0x95;
}*/
void Delay(int m)
{
while(--m);
}
void test_led(void) //LED测试程序
{
int i;
P1=0x7F;
Delay(20000);
for(i=0;i<7;i++)
{
P1=P1>>1;
Delay(20000);
}
P1=0xFF;
Delay(20000);
P1=0x00;
Delay(20000);
P1=0xFF;
Delay(20000);
P1=0x00;
Delay(20000);
P1=0xFF;
}
void test_digseg(void) //数码管测试程序
{
char i,j;
CE573=1;
for(i=0;i<16;)
{
for(j=0;j<4;j++)
{
P2=segsel[j];
P0=digseg[i];
i++;
Delay(20000);
}
}
P2=0xF0; // 4只数码管同时开启
P0=0xFF;
Delay(20000);
P0=0x00;
Delay(20000);
P0=0xFF;
// Delay(20000);
// P0=0x00;
// Delay(20000);
// P0=0xFF;
}
void test_beep(char n) //蜂鸣器响N次
{
char i;
for(i=0;i<n;i++)
{
BUZZER=0;
Delay(9000);
BUZZER=1;
Delay(9000);
}
}
/*************** 定义按键 ************/
char check_K1(void)
{
if(KEY1==0)
{
Delay(2000);
{
if(KEY1==0)
{
return 1;
}
}
}
return 0;
}
char check_K2(void)
{
if(KEY2==0)
{
Delay(2000);
{
if(KEY2==0)
{
return 1;
}
}
}
return 0;
}
char check_K3(void)
{
if(KEY3==0)
{
Delay(2000); // 按键去抖
{
if(KEY3==0)
{
return 1;
}
}
}
return 0;
}
char check_K4(void)
{
if(KEY4==0)
{
Delay(2000);
{
if(KEY4==0)
{
return 1;
}
}
}
return 0;
}
code uchar dis1[] = {"Hello MCU WORLD "} ;
code uchar dis2[] = {"LET'S BEGINNING "} ;
code uchar send_txt[]= {"123*\n* 456 *\n* 789 *\n*"};
void test_serial()
{
int i;
EA=0;
for(i=0;i<sizeof(send_txt);i++)
{
SBUF=send_txt[i];
while(TI==0);
TI=0;
}
EA=1;
}
//char key1_flag=0;
//char key2_flag=0;
/*void ext_int0() interrupt 0 //外部中断0服务程序
{
EA = 0;
Delay(4000);
key1_flag=1;
EA = 1;
}
void ext_int1() interrupt 2 //外部中断1服务程序
{
EA = 0;
Delay(4000);
key2_flag=1;
EA = 1;
}
*/
void getch(void) interrupt 4 //中断源编号为4,即串口中断
{
uchar m;
EA=0;
RI=0;
m=SBUF;
if(m==0x80) //向开发板串口发送的数据
{
test_serial();
}
EA=1;
}
void delay()
{
int i,j;
for(i=0; i<=100; i++)
for(j=0; j<=20; j++)
;
}
/************** LCD ***************************
/********************************************************************
* 名称 : enable(uchar del)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void enable(uchar del)
{
P0 = del;
RS = 0;
RW = 0;
E = 0;
delay();
E = 1;
delay();
}
/********************************************************************
* 名称 : write(uchar del)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/
void write(uchar del)
{
P0 = del;
RS = 1;
RW = 0;
E = 0;
delay();
E = 1;
delay();
}
/********************************************************************
* 名称 : L1602_init()
* 功能 : 1602初始化,请参考1602的资料
* 输入 : 无
* 输出 : 无
***********************************************************************/
void L1602_init(void)
{
enable(0x01);
enable(0x38);
enable(0x0c);
enable(0x06);
enable(0xd0);
}
/********************************************************************
* 名称 : L1602_char(uchar hang,uchar lie,char sign)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下
L1602_char(1,5,'b')
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void L1602_char(uchar hang,uchar lie,char sign)
{
uchar a;
if(hang == 1) a = 0x80;
if(hang == 2) a = 0xc0;
a = a + lie - 1;
enable(a);
write(sign);
}
/********************************************************************
* 名称 : L1602_string(uchar hang,uchar lie,uchar *p)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
L1602_string(1,5,"ab cd ef;")
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void L1602_string(uchar hang,uchar lie,uchar *p)
{
uchar a;
if(hang == 1) a = 0x80;
if(hang == 2) a = 0xc0;
a = a + lie - 1;
enable(a);
while(1)
{
if(*p == '\0') break;
write(*p);
p++;
}
}
/********************************************************************
* 名称 : test_1602()
* 功能 : LCD主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void test_1602()
{
uchar i = 48;
L1602_init();
L1602_char(1,5,'b');
L1602_string(1,1," 0123456789 ");
L1602_string(2,1," ABCDEDGHIJ ");
}
/************* 18B20 ************************
/****************************************************************************/
void ds1820disp( uint tvalue1) ;
void display(uchar a1,uchar a2,uchar a3,uchar a4);
uint tvalue;
uchar disdata[]={0,0,0,0};
/****************************************************************************/
void delaytimer(void)
{
EA=1;
TMOD=0x10;
TL1=(65536-500)%256;
TH1=(65536-500)/256;
TR1=0;
ET1=1;
}
void timer() interrupt 3
{
TR1=0;
TH1=(65536-500)/256;
TL1=(65536-500)%256;
BUZZER=~BUZZER;
}
void delay_18B20( uint i) //延时
{
while(--i);
}
void delay2(uchar n) //延时
{
uchar i,j;
for(i=n;i>0;i--)
for(j=20;j>0;j--);
}
void ds1820rst() //初始化DS18B20
{
unsigned char x=0;
DQ = 1; //DQ复位
delay_18B20(4); //
DQ = 0; //单片机将DQ拉低
delay_18B20(60); //
DQ = 1; //拉高总线
delay_18B20(14);//
x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay_18B20(20);
}
uchar ds1820rd() //从DS18B20读取一字节
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--) //一位一位地读,共8位
{
DQ = 0; //给一脉冲信号
dat>>=1; //dat往右移一位
DQ = 1; //给一脉冲信号
if(DQ)
dat|=0x80;
delay_18B20(4);//
} return(dat);
}
void ds1820wr(uchar wdata) //写入一字节
{
unsigned char i=0;
for (i=8;i>0;i--)
{
DQ = 0;
DQ = wdata&0x01;
delay_18B20(5);
DQ = 1;
wdata>>=1;
}
}
uint read_temp() //读取温度
{
float aaa;
uchar a,b;
ds1820rst();
ds1820wr(0xcc); //向DS18B20发跳过读ROM命令
ds1820wr(0x44); //启动DS18B20进行温度转换命令,转换结果存入内部RAM
delay_18B20(80); //延时
ds1820rst();
ds1820wr(0xcc); //向DS18B20发跳过读ROM命令
ds1820wr(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
delay_18B20(80); //延时
a=ds1820rd(); //读内部RAM 低位
b=ds1820rd(); //读内部RAM 高位
aaa=(b*256+a)*6.25;
tvalue=(uint)aaa;
return(tvalue);
}
void ds1820disp( unsigned int tvalue1) //温度处理
{
disdata[0]=tvalue1/1000; //十位
disdata[1]=tvalue1%1000/100; //个位
disdata[2]=tvalue1%100/10; //小数点后一位
disdata[3]=tvalue1%10;; //小数点后两位
display(disdata[0],disdata[1],disdata[2],disdata[3]);
}
void display(uchar a1,uchar a2,uchar a3,uchar a4) //显示温度
{
P2=0xfe;
P0=table[a1];
delay2(20);
P2=0xfd;
P0=table1[a2];
delay2(20);
P2=0xfb;
P0=table[a3];
delay2(20);
P2=0xf7;
P0=table[a4];
delay2(20);
}
void led(unsigned int lim) //设置温度临界植
{
if(lim/100<30) //低于30度,亮绿灯
P1=0xdf;
else if(lim/100<31) //低于31度,高于30度,亮黄灯
P1=0xbf;
else
{ P1=0x7f; //高于31度,亮红灯。蜂鸣器报警
TR1=1;}
}
void test_18B20()
{
uint temp;
delaytimer();
while(1)
{
temp=read_temp();
ds1820disp(temp);
led(temp);
if (check_K4()) //如果检测到有按键,跳出循环
{
break;
}
else if(check_K2())
{
break;
}
else if(check_K1())
{
break;
}
}
}
/*********************** music ****************************/
//生日快乐歌的音符频率表,不同频率由不同的延时来决定
uchar code SONG_TONE[]={212,212,190,212,159,169,212,212,190,212,142,159,
212,212,106,126,159,169,190,119,119,126,159,142,159,0};
//生日快乐歌节拍表,节拍决定每个音符的演奏长短
uchar code SONG_LONG[]={9,3,12,12,12,24,9,3,12,12,12,24,
9,3,12,12,12,12,12,9,3,12,12,12,24,0};
//延时
void DelayMS(uint x)
{
uchar t;
while(x--) for(t=0;t<120;t++);
}
//播放函数
void PlayMusic()
{
uint i=0,j,k;
while(SONG_LONG[i]!=0||SONG_TONE[i]!=0)
{ //播放各个音符,SONG_LONG 为拍子长度
for(j=0;j<SONG_LONG[i]*20;j++)
{
BUZZER=~BUZZER;
//SONG_TONE 延时表决定了每个音符的频率
for(k=0;k<SONG_TONE[i]/3;k++);
}
DelayMS(10);
i++;
if (check_K4()) //如果检测到有按键,跳出循环
{
break;
}
else if(check_K3())
{
break;
}
else if(check_K1())
{
break;
}
}
}
void music()
{
BUZZER=0;
PlayMusic(); //播放生日快乐
DelayMS(300); //播放完后暂停一段时间
BUZZER=1;
}
/*********************** main ****************************/
main()
{
// initmpu();
test_led(); //测试LED
test_1602(); //测试LCD
test_digseg(); //测试数码管
test_beep(2); //蜂鸣器响4声
test_serial(); //测试串口
P0=0XBF;
while(1) // 扫描4个自由按键
{
if(check_K1()) //按1键
{
P0=digseg[1];
test_beep(1); //驱动蜂鸣器
}
else if(check_K2())//按2键
{
// key2_flag=0;
P0=digseg[2];
test_beep(1);
music(); //播放歌曲生日快乐
}
else if(check_K3())//按3键
{
P0=digseg[3];
test_beep(1);
test_18B20(); //测试温度传感器
}
else
if(check_K4())//按4键
{
P1 = 0xfe;
P0=digseg[4];
P2 = 0XFF;
test_beep(1);
infrared(); //测试红外模块
}
}
}根据示例代码制作一个的智能闹钟
最新发布