//这是一个CH451芯片驱动的数码管+按键+ds1302电子表+ds18b20温度的c语言程序
//已经在51单片机开发板上测试通过,带有温度报警,有详细的注释.
//程序的完整版本下载地址:http://www.51hei.com/f/ch451.rar
//本程序版权所无您可以随意修改.
#include <reg51.h>
#include <math.h>
#include <intrins.h>
/*************************************************************
_crol_ 字符循环左移
_cror_ 字符循环右移
_irol_ 整数循环左移
_iror_ 整数循环右移
_lrol_ 长整数循环左移
_lror_ 长整数循环右移
_nop_ 空操作8051 NOP 指令
*************************************************************/
#define uchar unsigned char
#define uint unsigned int
/******************************DS1302宏定义******************/
#define WRITE_SECOND 0x80
#define WRITE_MINUTE 0x82
#define WRITE_HOUR 0x84
#define READ_SECOND 0x81
#define READ_MINUTE 0x83
#define READ_HOUR 0x85
#define WRITE_PROTECT 0x8E
/***********************CH451宏定义************************/
#define CH451_RESET 0x0201 //复位
#define CH451_LEFTMOV 0x0300 //设置移动方式-作移
#define CH451_LEFTCYC 0x0301 //设置移动方式-左循
#define CH451_RIGHTMOV 0x0302 //设置移动方式-右移
#define CH451_RIGHTCYC 0x0303 //设置移动方式-右循
#define CH451_SYSOFF 0x0400 //关显示、键盘、看门狗
#define CH451_SYSON1 0x0401 //开显示
#define CH451_SYSON2 0x0403 //开显示、键盘
#define CH451_SYSON3 0x0407 //开显示、键盘、看门狗功能
#define CH451_DSP 0x0500 //设置默认显示方式
#define CH451_BCD 0x0580 //设置BCD译码方式
#define CH451_TWINKLE 0x0600 //设置闪烁控制——正常显示
#define CH451_DIG0 0x0800 //数码管位0显示
#define CH451_DIG1 0x0900 //数码管位1显示
#define CH451_DIG2 0x0a00 //数码管位2显示
#define CH451_DIG3 0x0b00 //数码管位3显示
#define CH451_DIG4 0x0c00 //数码管位4显示
#define CH451_DIG5 0x0d00 //数码管位5显示
#define CH451_DIG6 0x0e00 //数码管位6显示
#define CH451_DIG7 0x0f00 //数码管位7显示
/*************************************************************/
sbit ACC_7=ACC^7; //位寻址寄存器定义
sbit SCLK=P2^1; //ds1302管脚定义
sbit IO=P2^0;
sbit RST=P1^7;
sbit DQ=P1^6; //ds18b20定义
sbit P26=P2^6;
sbit ch451_dclk=P3^4; //串行数据时钟上升延激活
sbit ch451_din=P3^3; // 串行数据输出,接CH451的数据输人
sbit ch451_load=P2^3; //串行命令加载,上升延激活
sbit ch451_dout=P2^2; //键值数据输入,接ch451数据输出
int temp;
int tt; //真实温度变量
uchar ch451_key=0; // 存放键盘中断中读取的键值
uint display[8]={0x0a00,0x0900,0x0b00,0x0800,
0x0c00,0x0d00,0x0e00,0x0f00};
uchar BCD[10]={0xbe,0x24,0xea,0xe6, //0,1,2,3,
0x74,0xd6,0xde,0xa4, //4,5,6,7,
0xfe,0xf6 //8,9
};
/*************精确延时函数*****************/
void delay(uint i)
{
while(–i);
}
/************************蜂鸣器程序********/
void speaker(void)
{
uchar i,j;
for(j=0;j<250;j++)
for(i=0;i<250;i++)
{
P26=~P26;
for(i=0;i<250;i++);
}
P26=1; //防止结束时候是低电平
}
/**********************4*******************/
/*****************DS18B20******************/
void Init_Ds18b20(void) //DS18B20初始化
{
DQ=0; //单片机拉低总线
delay(500); //精确延时,维持至少480us
DQ=1; //释放总线,即拉高了总线
delay(200); //此处延时有足够,确保能让DS18B20发出存在脉冲。
}
/*****************************************************************************************/
uchar Read_One_Byte() //读取一个字节的数据
//读数据时,数据以字节的最低有效位先从总线移出
{
uchar i=0;
uchar dat=0;
for(i=8;i>0;i–)
{
DQ=0; //将总线拉低,要在1us之后释放总线
//单片机要在此下降沿后的15us内读数据才会有效。
_nop_();
_nop_(); //至少维持了1us,表示读时序开始
dat>>=1; //让从总线上读到的位数据,依次从高位移动到低位。
DQ=1; //释放总线,此后DS18B20会控制总线,把数据传输到总线上
delay(1); //延时7us,此处参照推荐的读时序图,尽量把控制器采样时间放到读时序后的15us内的最后部分
if(DQ) //控制器进行采样
{
dat|=0x80; //若总线为1,即DQ为1,那就把dat的最高位置1;若为0,则不进行处理,保持为0
}
delay(60); //此延时不能少,确保读时序的长度60us–很重要
}
return (dat);
}
/********************************************************/
void Write_One_Byte(uchar dat)
{
uchar i=0;
for(i=8;i>0;i–)
{
DQ=0; //拉低总线
_nop_();
nop_(); //至少维持了1us,表示写时序(包括写0时序或写1时序)开始
DQ=dat&0x01; //从字节的最低位开始传输
//指令dat的最低位赋予给总线,必须在拉低总线后的15us内,
//因为15us后DS18B20会对总线采样。
delay(60); //必须让写时序持续至少60us —-很重要
DQ=1; //写完后,必须释放总线,
/* _nop_(); */
dat>>=1;
//因为15us后DS18B20会对总线采样。
delay(1);
}
}
/*************************************************************************/
uint Get_Tmp() //获取温度
{
float t;
uchar a=11,b=0;
Init_Ds18b20(); //初始化
Write_One_Byte(0xcc); //忽略ROM指令
Write_One_Byte(0x44); //温度转换指令
Init_Ds18b20(); //初始化
Write_One_Byte(0xcc); //忽略ROM指令
Write_One_Byte(0xbe); //读读RAM的存储器指令
a=Read_One_Byte(); //读取到的第一个字节为温度LSB
b=Read_One_Byte(); //读取到的第二个字节为温度MSB
temp=b; //先把高八位有效数据赋于temp
temp<<=8; //把以上8位数据从temp低八位移到高八位
temp=temp|a; //两字节合成一个整型变量
t=temp*0.0625; //得到真实十进制温度值
//因为DS18B20可以精确到0.0625度
//所以读回数据的最低位代表的是0.0625度
temp=t*10+0.5; //此处放大十倍
//这样做的目的将小数点后第一位也转换为可显示数字
//同时进行一个四舍五入操作。
return(temp);
}
/************************************************************************
以上实现温度传感器的读取数据
*************************************************************************/
/******************************DS1302*************************************/
//地址、数据发送子程序
void Write1302(uchar addr,uchar dat )
{
uchar i,t;
RST=0; //RST 引脚为低,数据传送终止
SCLK=0; //清零时钟总线
RST=1; //RST 引脚为高,逻辑控制有效
//发送地址
for(i=8;i>0;i–) //循环8次移位
{
SCLK=0;
t=addr;
IO=(bit)(t&0x01); //每次传输低字节
addr>>=1; //右移一位
SCLK=1;
}
//发送数据
for(i=8;i>0;i–)
{
SCLK=0;
t=dat;
IO=(bit)(t&0x01);
dat>>=1;
SCLK=1;
}
RST=0;
}
//数据读取子程序
uchar Read1302(uchar addr )
{
uchar i,t,dat1,dat2;
RST=0;
SCLK=0;
RST=1;
//发送地址
for(i=8;i>0;i–) //循环8次移位
{
SCLK=0;
t=addr;
IO=(bit)(t&0x01); //每次传输低字节
addr>>=1; //右移一位
SCLK=1;
}
//读取数据
for(i=8;i>0;i–)
{
ACC_7=IO;
SCLK=1;
ACC>>=1; //右移
SCLK=0;
}
RST=0;
dat1=ACC;
dat2=dat1/16; //数据进制转换
dat1=dat1%16; //十六进制转十进制
dat1=dat1+dat2*10;
return (dat1);
}
//初始化DS1302
void Initial(void)
{
Write1302 (WRITE_PROTECT,0x00); //禁止写保护
Write1302 (WRITE_SECOND,0x00); //秒位初始化,开始计时
Write1302 (WRITE_MINUTE,0x03); //分钟初始化
Write1302 (WRITE_HOUR,0x23); // 小时初始化——24小时模式
//Write1302 (WRITE_PROTECT,0x80); // 允许写保护
// 调试证明必须禁止写保护
//不然修改不了初始值
}
/*********************************CH451**********************/
//********************************************
//设置定时器中断__定时扫描键盘
void ch451_init()
{
ch451_din=0; //先低后高,选择4线输入
ch451_din=1;
TMOD=0x10; //设置定时器T1工作在16位计时状态
EA=1; //开中断总开关
ET1=1; //允许中断
TR1=1; //开中断
PT1=0; //设置低优先级
TL1=1; //装载计数初值
TH1=0; //此计数初值用来调试
}
//*****************************************************
//定义一无符号整型变量存储12字节的命令字。
void ch451_write(uint command)
{
uchar i;
TR1=0; //禁止T1中断
ch451_load=0; //命令开始
for(i=0;i<12;i++){ //送入12位数据,低位在前
ch451_din=command&1;
ch451_dclk=0;
command>>=1;
ch451_dclk=1; //上升沿有效
}
ch451_load=1; //上升沿加载数据
TR1=1; // 开启T1中断
}
//*************************************************
//*************************************************
//中断子程序 使用定时器中断T1,寄存器组1
void ch451_inter() interrupt 3 using 1
{
uchar i; //定义循环变量
uchar command,keycode; //定义控制字寄存器,和中间变量定时器
command=0x07; //读取键值命令的高4位0111B
ch451_load=0; //命令开始
for(i=0;i<4;i++){
ch451_din=command&1; //低位在前,高位在后
ch451_dclk=0;
command>>=1; //右移一位
ch451_dclk=1; //产生时钟上升沿锁通知CH451输入位数据
}
ch451_load=1; //产生加载上升沿通知CH451处理命令数据
keycode=0; //清除keycode
for(i=0;i<7;i++){
keycode<<=1; //数据作移一位,高位在前,低位在后
keycode|=ch451_dout; //从高到低读入451的数据
ch451_dclk=0; //产生时钟下升沿通知CH451输出下一位
ch451_dclk=1;
}
ch451_key=keycode; //保存上次的键值
TL1=1; //重新装载计数初值
TH1=0; //此计数初值用来调试
}
//***********************************************
void main()
{
int HIGH=270; //定义温度上限变量
uchar A0,A1,A2,A3; //记录温度各位数的变量
uchar b,c; //定义存放DS1302中数据的变量
P26=1; //关闭蜂鸣器
Initial(); //初始化DS1302
//初始化以后此语句必须关掉 防止每次上电初始化DS1302
//关掉此语句编译时会为此产生一个警告
/*改动*/
ch451_init(); // 设置定时器中断__定时扫描键盘
ch451_write(CH451_RESET); //CH451复位
ch451_write(CH451_SYSON2); //开显示、键盘
ch451_write(CH451_DSP); //设置BCD不译码方式 由于板画错了 此设置很重要
ch451_write(CH451_TWINKLE); //设置闪烁控制——正常显示
while(1)
{
tt=Get_Tmp(); //读出当前温度
A3=tt/1000; //千位
A2=(tt%1000)/100; //百位
A1=(tt%100)/10; //十位——这么处理的目的是显示小数点,因为A1实际是温度的个位
A0=tt%10; //个位
ch451_write(display[0]+BCD[A0]); //显示温度小数位
ch451_write(display[1]+BCD[A1]+1); //显示温度个位 此处加一为了加入小数点
ch451_write(display[2]+BCD[A2]); //显示温度十位
ch451_write(display[3]+BCD[A3]); //显示温度百位
if(Get_Tmp()>HIGH) //如果温度大于上限度
{
delay(10); //延时是为了防止脉冲不稳定干扰
if(Get_Tmp()>HIGH) //可以消除蜂鸣器非正常响
/*合理的改动*/
{
Write1302(0xc0,Read1302(READ_MINUTE)/10*16+Read1302(READ_MINUTE)%10); //写入当前记录的数据所对应的时间——分
Write1302(0xc2,Read1302(READ_HOUR)/10*16+Read1302(READ_HOUR)%10); //写入当前记录的数据所对应的时间——小时
/**写入的应该是16进制而不是十进制**/
speaker(); //如果温度大于 HIGH度,蜂鸣器报警
}
}
if(Get_Tmp()<0) //如果温度小于0度
{
delay(10); //延时是为了防止脉冲不稳定干扰
if(Get_Tmp()<0) //可以消除温度非正常显示为负
/*合理的改动*/
{
tt=abs(tt);
ch451_write(display[0]+BCD[A0]); //显示温度小数位
ch451_write(display[1]+BCD[A1]+1); //显示温度个位 此处加一为了加入小数点
ch451_write(display[2]+BCD[A2]); //显示温度十位
ch451_write(display[3]+BCD[A2]); //显示温度百位
ch451_write(display[4]+0x40); //显示负号
}
}
//对各个按键进行定义
switch(ch451_key)
{
case 0x40: {
b=Read1302(0xc1); //读出数据所对应的时间——分
c=Read1302(0xc3); //读出数据所对应的时间——小时 */
ch451_write(display[4]+BCD[b%10]); //显示分钟个位
ch451_write(display[5]+BCD[b/10]); //显示分钟十位
ch451_write(display[6]+BCD[c%10]); //显示小时个位
ch451_write(display[7]+BCD[c/10]); //显示小时十位
} break; //按下第1个键时调出DS1302中产生温度报警的时间
case 0x43: { ch451_write(display[4]+0); //关显示分钟个位
ch451_write(display[5]+0); //关显示分钟十位
ch451_write(display[6]+0); //关显示小时个位
ch451_write(display[7]+0); //关显示小时十位;
} break; //按下第2个键关时间显示
case 0x41: speaker(); break; //按下第3个键时蜂鸣器响
case 0x42: {
A3=HIGH/1000; //千位
A2=(HIGH%1000)/100; //百位
A1=(HIGH%100)/10; //十位——这么处理的目的是显示小数点,因为A1实际是温度的个位
A0=HIGH%10; //个位
ch451_write(display[4]+BCD[A0]); //显示温度小数位
ch451_write(display[5]+BCD[A1]+1); //显示温度个位 此处加一为了加入小数点
ch451_write(display[6]+BCD[A2]); //显示温度十位
ch451_write(display[7]+BCD[A3]); //显示温度十位
} break; //按下第4个键显示上限温度
case 0x48: {
delay(65000); //使按键增大温度上限值得过程变慢
HIGH=HIGH+1;
A3=HIGH/1000; //千位
A2=(HIGH%1000)/100; //百位
A1=(HIGH%100)/10; //十位——这么处理的目的是显示小数点,因为A1实际是温度的个位
A0=HIGH%10; //个位
ch451_write(display[4]+BCD[A0]); //显示温度小数位
ch451_write(display[5]+BCD[A1]+1); //显示温度个位 此处加一为了加入小数点
ch451_write(display[6]+BCD[A2]); //显示温度十位
ch451_write(display[7]+BCD[A3]); //显示温度百位
} ; break; //按下第5个键增加温度上限值
case 0x4b: {
delay(65000); //使按键减小温度上限值得过程变慢
HIGH=HIGH-1;
A3=HIGH/1000; //千位
A2=(HIGH%1000)/100; //百位
A1=(HIGH%100)/10; //十位——这么处理的目的是显示小数点,因为A1实际是温度的个位
A0=HIGH%10; //个位
ch451_write(display[4]+BCD[A0]); //显示温度小数位
ch451_write(display[5]+BCD[A1]+1); //显示温度个位 此处加一为了加入小数点
ch451_write(display[6]+BCD[A2]); //显示温度十位
ch451_write(display[7]+BCD[A3]); //显示温度十位
} ; break; //按下第6个键减小温度上限值
case 0x49: {
while(ch451_key!=0x43)
{
ch451_write(display[0]+BCD[Read1302(READ_SECOND)%10]); //显示分钟的个位
ch451_write(display[1]+BCD[Read1302(READ_SECOND)/10]); //显示秒的十位
ch451_write(display[2]+0x40); //显示负号
ch451_write(display[3]+BCD[Read1302(READ_MINUTE)%10]); //显示分钟的个位
ch451_write(display[4]+BCD[Read1302(READ_MINUTE)/10]); //显示分钟的十位
ch451_write(display[5]+0x40); //显示负号
ch451_write(display[6]+BCD[Read1302(READ_HOUR)%10]); //显示小时的个位
ch451_write(display[7]+BCD[Read1302(READ_HOUR)/10]); //显示分钟的十位
}
} ; break; //按下第7个键动态显示当前的时间——电子表
case 0x4a: ; break; //按下第8个键无效
}
/****************************************************************/
}
}
CH451驱动的数码管+按键+电子表+温度程序
未经允许不得转载:huangea的博客 » CH451驱动的数码管+按键+电子表+温度程序
看似很简单的一句话,或许都能给人以启发,支持一小下
哈哈,网站做的不错,支持。。。。。