每次建好工程文件夹,里边包含User(放工程文件,mian.c,可以在这里写如同我这个文章的文本文档)、Driver(存放底层文件如Led.c,Led.h等)
新建的工程先搭建框架,可以先书写底层函数(此次书写了六个函数并包含相应的头文件共十二个底层文件)
比如先用3个IO口控制74HC138译码器,控制Y4为低电平;当Y4为低电平时,或非门74HC02控制Y4C为高电平,使74HC573的OE端口有效,OE端口有效时,可使用P0口控制LED的亮灭。
可以去多了解74HC138译码器,74HC02或非门,74HC573八路输出透明锁存器的相关内容会更好理解
#include
//关闭外设
void System_Init()
{
P0 = 0xff;
P2 = P2 & 0x1f | 0x80;
P2 &= 0x1f;
P0 = 0x00;
P2 = P2 & 0x1f | 0xa0;
P2 &= 0x1f;
}
//头文件
#include
void System_Init();
与初始化底层驱动专用文件同理,需要了解对应的锁存器控制,可以在使用的芯片数据手册查看
#include
void Led_Disp(unsigned char addr,enable)//LED
{
static unsigned char temp = 0x00;
static unsigned char temp_Old = 0xff;
if(enable)
temp |=0x01 << addr;
else
temp&= ~ (0x01 << addr);
if(temp != temp_Old)
{
P0 = ~ temp;
P2 = P2 & 0x1f | 0x80;
P2 &= 0x1f;
temp_Old = temp;
}
}
void Beep(unsigned char flag)//蜂鸣器
{
static unsigned char temp = 0x00;
static unsigned char temp_Old = 0xff;
if(flag)
temp |=0x40 ;
else
temp &= ~ 0x40 ;
if(temp != temp_Old)
{
P0 = ~ temp;
P2 = P2 & 0x1f | 0xa0;
P2 &= 0x1f;
temp_Old = temp;
}
}
void Relay(unsigned char flag)//继电器
{
static unsigned char temp = 0x00;
static unsigned char temp_Old = 0xff;
if(flag)
temp |= 0x10 ;
else
temp &= ~ 0x10 ;
if(temp != temp_Old)
{
P0 = ~ temp;
P2 = P2 & 0x1f | 0xa0;
P2 &= 0x1f;
temp_Old = temp;
}
}
//头文件
#include
void Led_Disp(unsigned char addr,enable);
(板子上的按键从按键4开始到按键19,可根据实际硬件修改)
#include
unsigned char Key_Read()
{
unsigned char temp = 0;
if(P33 == 0)temp = 4;//独立按键
if(P32 == 0)temp = 5;
if(P31 == 0)temp = 6;
if(P30 == 0)temp = 7;
// P44 = 0; P42 = 1; P35 = 1; P34 = 1;//矩阵按键
// if(P33 == 0)temp = 4;
// if(P32 == 0)temp = 5;
// if(P31 == 0)temp = 6;
// if(P30 == 0)temp = 7;
// P44 = 1; P42 = 0; P35 = 1; P34 = 1;
// if(P33 == 0)temp = 8;
// if(P32 == 0)temp = 9;
// if(P31 == 0)temp = 10;
// if(P30 == 0)temp = 11;
// P44 = 1; P42 = 1; P35 = 0; P34 = 1;
// if(P33 == 0)temp = 12;
// if(P32 == 0)temp = 13;
// if(P31 == 0)temp = 14;
// if(P30 == 0)temp = 15;
// P44 = 1; P42 = 1; P35 = 1; P34 = 0;
// if(P33 == 0)temp = 16;
// if(P32 == 0)temp = 17;
// if(P31 == 0)temp = 18;
// if(P30 == 0)temp = 19;
return temp;
}
//头文件
#include
unsigned char Key_Read();
#include
unsigned char Seg_Dula[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc6,0x8c};//数码管段码储存数组
unsigned char Seg_Wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//数码管位码储存数组
void Seg_Disp(unsigned char wela,dula,point)//数码管显示函数
{
P0 = 0xff; //
P2 = P2 & 0x1f |0xe0;
P2 &= 0x1f;
P0 = Seg_Wela[wela];
P2 = P2 & 0x1f |0xc0;
P2 &= 0x1f;
P0 = Seg_Dula[dula];
if(point)
P0 &= 0x7f;
P2 = P2 & 0x1f |0xe0;
P2 &= 0x1f;
}
//头文件
#include
void Seg_Disp(unsigned char wela,dula,point);
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include "iic.h"
#include "intrins.h"
#define DELAY_TIME 5
#define Photo_Res_Channel 0x41
#define Adj_Res_Channel 0x43
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit; // 0:应答,1:非应答
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}
//入口参数:要进行转换的数值
//返回值:无
//函数功能:对入口参数要转换的DA数据进行转换
void Da_Write(unsigned char dat)
{
IIC_Start();//发送开启信号
IIC_SendByte(0x90);//选择PCF8591芯片,确定写的模式
IIC_WaitAck();//等待PCF8591反馈
IIC_SendByte(0x41);//使能DA转换(随便写通道编号,不影响,主要的功能是使能DA)
IIC_WaitAck();//等待PCF8591反馈
IIC_SendByte(dat);//将待转换的数据发送出去
IIC_WaitAck();//等待PCF8591反馈
IIC_Stop();//停止发送
}
//头文件
# include "STC15F2K60S2.H"
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
//函数名:DAC转换函数
//入口参数:要进行转换的数值
//返回值:无
//函数功能:对入口参数要转换的DA数据进行转换
void Da_Write(unsigned char dat);
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "onewire.h"
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t) //12T 或1T,根据需要修改
{
t *= 12;//用了温度这句必须写,设置为12T,这句官方不会写,这两句和下面的功能一样
while(t--);
// unsigned char i;
// while(t--)
// {
// for(i=0;i<12;i++);
// }
}
void Write_DS18B20(unsigned char dat)//写
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
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(5);
}
return dat;
}
bit init_ds18b20(void)//初始化
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//入口参数:无
//函数功能:完成温度转换,并返回转换之后的温度数据
float Read_Temperature()
{
unsigned char high,low;//返回温度数据的低八位和高八位
init_ds18b20();//初始化
Write_DS18B20(0xcc);//跳过ROM
Write_DS18B20(0x44);//开始温度转换
init_ds18b20();//初始化
Write_DS18B20(0xcc);//跳过ROM
Write_DS18B20(0xbe);//读取温度
low = Read_DS18B20();//读取低位
high = Read_DS18B20();//读取高位
return((high << 8)|low) / 16.0;//返回温度保留后两位精度数据
}
//头文件
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
float Read_Temperature();
#endif
/*头文件声明区*/
#include
#include "Init.h"//初始化底层驱动专用头文件
#include "Key.h"//按键底层驱动专用头文件
#include "Led.h"//Led底层驱动专用头文件
#include "Seg.h"//数码管底层驱动专用头文件
#include "onewire.h"//温度底层驱动专用头文件
#include "iic.h"//DAC底层驱动专用头文件
/*变量声明区*/
unsigned char Key_Val,Key_Old,Key_Down,Key_Up;//按键扫描专用变量
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned char Key_Slow_Down;//按键减速变量
unsigned char Seg_Slow_Down;//数码管减速变量
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管数据存放数组
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//LED数据存放数组
bit Seg_Disp_Mode;//数码管显示模式 0-数据界面 1-参数界面
unsigned char Temperature;//实时温度数据
unsigned char Temp_Disp[2] = {30,20};//温度变量显示数组
unsigned char Temp_Ctrol[2] = {30,20};//温度变量控制数组
bit Temp_Index = 1;//参数数组指针
bit Error_Flag;//错误设置标志位
/*键盘处理函数*/
void Key_Proc()
{
if(Key_Slow_Down)return;
Key_Slow_Down = 1;//键盘减速程序
Key_Val = Key_Read();//实时读取键码值
Key_Down = Key_Val & (Key_Val ^ Key_Old);//捕捉按键下降沿
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//捕捉按键上升沿
Key_Old = Key_Val;//辅助扫描变量
switch(Key_Down)
{
case 4://界面切换
Seg_Disp_Mode ^= 1;//循环切换数据界面和参数界面
if(Seg_Disp_Mode == 1)//从数据界面切换到参数界面
{
//上下限指针复位
Temp_Index = 0;
//将控制值赋值给显示数组 便于修改数据
Temp_Disp[0] = Temp_Ctrol[0];
Temp_Disp[1] = Temp_Ctrol[1];
}
else//从参数界面切换到数据界面
{
if(Temp_Disp[0] >= Temp_Disp[1])
{
//标志位拉低 表示设置正确
Error_Flag = 0;
//将显示值赋值给控制数组 用于保存数据
Temp_Ctrol[0] = Temp_Disp[0];
Temp_Ctrol[1] = Temp_Disp[1];
}
else
Error_Flag = 1;//标志位拉高 表示设置错误
}
break;
case 5://参数切换
if(Seg_Disp_Mode == 1) //处于参数界面
Temp_Index ^= 1;//切换参数选中上下限
break;
case 6://参数自加
if(Seg_Disp_Mode == 1)//处于参数界面
{
if(++Temp_Disp[Temp_Index] == 100)
Temp_Disp[Temp_Index] = 99;//限制上限到99
}
break;
case 7://参数自减
if(Seg_Disp_Mode == 1)//处于参数界面
{
if(--Temp_Disp[Temp_Index] == 255)
Temp_Disp[Temp_Index] = 0;//限制下限到0
}
break;
}
}
/*信息处理函数*/
void Seg_Proc()
{
if(Seg_Slow_Down)return;
Seg_Slow_Down = 1;//数码管减速程序
/*信息获取区*/
Temperature = Read_Temperature();//实时读取温度值
/*数据显示区*/
if(Seg_Disp_Mode == 0)//处于数据界面
{
Seg_Buf[0] = 11;//显示C
Seg_Buf[3] = 10;
Seg_Buf[4] = 10;
Seg_Buf[6] = (unsigned char) Temperature / 10 % 10;
Seg_Buf[7] = (unsigned char) Temperature % 10;
}
else //处于参数界面
{
Seg_Buf[0] = 12;//显示P
Seg_Buf[3] = Temp_Disp[0] / 10 % 10;
Seg_Buf[4] = Temp_Disp[0] % 10;
Seg_Buf[6] = Temp_Disp[1] / 10 % 10;
Seg_Buf[7] = Temp_Disp[1] % 10;
}
}
/*其他函数*/
void Led_Proc()
{
unsigned char i;//For循环专用变量
/*LED相关*/
ucLed[0] = (Temperature > Temp_Ctrol[0]);
ucLed[1] = (Temperature <= Temp_Ctrol[0] && Temperature >= Temp_Ctrol[1]);
ucLed[2] = (Temperature < Temp_Ctrol[1]);
ucLed[3] = Error_Flag;
/*DAC相关*/
for(i = 0;i<3;i++)
{
if(ucLed[i] == 1)
{
Da_Write(51*(4-i));
break;
}
}
}
(这个可以使用STC的定时器计算那里生成c代码,后面要自己添加ET0,EA打开中断)
/*定时器0初始化函数*/
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器中断0打开
EA = 1; //总中断打开
}
(为了定时执行特定的任务,如此处设置了定时的时间触发了数码管和LED产生特定反应)
/*定时器中断服务函数*/
void Timer0server()interrupt 1
{
if(++Key_Slow_Down == 10)Key_Slow_Down = 0;//键盘减速专用
if(++Seg_Slow_Down == 500)Seg_Slow_Down = 0;//数码管减速专用
if(++Seg_Pos == 8)Seg_Pos = 0;//数码管显示专用
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}
void Delay750ms() //@12.000MHz
{
unsigned char i, j, k;
i = 35;
j = 51;
k = 182;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/*Main*/
void main()
{
Read_Temperature();//上电读取一次温度并且延时750MS避免数据出现85,并且延时750ms让这个85不显示
Delay750ms();
Sys_Init();
Timer0Init();
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
关于DS18B20和PCF8591以及DAC转换等相关资料,可以搜素对应的数据手册查找观看,在其他篇文章里,对应主题的内容也有相应的部分资料可以查阅