一、根据硬件框图初始化好要使用的外设
推测出外设类型:
PCF8591、矩阵按键、AT24C02、LED、数码管(定时器)
创建工程模板:
(1)主函数:
#ifndef PBBLIC_H
#define PBBLIC_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void Close_All();
#endif
(2)公共函数:
#ifndef PBBLIC_H
#define PBBLIC_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void Close_All();
#endif
#include "Public.h"
/*
向某个锁存器发送信息
*/
void Select(u8 cs,u8 s_data)
{
P0 = s_data;
P2 = P2 & 0x1f | (cs<<5);
P2 &= 0x1f;
}
/*
关闭无关设备
*/
void Close_All()
{
//关闭蜂鸣器和继电器
Select(5,0x00);
//关闭LED
Select(4,0xff);
//清空数码管数据
Select(7,0xff);
}
LED灯:
(1)主函数:
#include "Public.h"
#include "Simple_Device.h"
void main()
{
Close_All();
LED_Show(0xff);
}
(2)LED函数:
#ifndef SIMPLE_DEVICE_H
#define SIMPLE_DEVICE_H
#include "Public.h"
void LED_Show(u8 l_data);
#endif
#include "Simple_Device.h"
/*
根据输入的8位数显示LED,其中1为亮灯
*/
void LED_Show(u8 l_data)
{
Select(4,~l_data);
}
数码管:
(1)主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
void Key_Proc();
void SEG_Proc();
void main()
{
Close_All();
Timer0_Init();
while(1)
{
SEG_Proc();
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
sprintf(COT,"%u%u",(u16)1234,(u16)5678);
SEG_TSL(COT,COD);
}
void Timer0_Isr(void) interrupt 1
{
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
}
(2)数码管函数:
#ifndef SEG_H
#define SEG_H
#include "Public.h"
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 COD,u8 PIS);
#endif
#include "SEG.h"
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
/*
输入字符串输出数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0;
for(i=0;i<8;i++)
{
switch(input[i])
{
case '0':output[i] = Seg_Table[0];break;
case '1':output[i] = Seg_Table[1];break;
case '2':output[i] = Seg_Table[2];break;
case '3':output[i] = Seg_Table[3];break;
case '4':output[i] = Seg_Table[4];break;
case '5':output[i] = Seg_Table[5];break;
case '6':output[i] = Seg_Table[6];break;
case '7':output[i] = Seg_Table[7];break;
case '8':output[i] = Seg_Table[8];break;
case '9':output[i] = Seg_Table[9];break;
default:output[i] = 0xff;
}
}
}
/*
数码管显示函数
*/
void SEG_Show(u8 COD,u8 PIS)
{
//消隐
Select(7,0xff);
//位选
Select(6,0x01<<PIS);
//段选
Select(7,COD);
}
矩阵按键:
(1)主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
void Key_Proc();
void SEG_Proc();
void main()
{
Close_All();
Timer0_Init();
while(1)
{
// SEG_Proc();
Key_Proc();
}
}
void Key_Proc()
{
u8 key_now,key_dwon;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon)
{
sprintf(COT,"%u",(u16)key_dwon);
SEG_TSL(COT,COD);
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
sprintf(COT,"%u%u",(u16)1234,(u16)5678);
SEG_TSL(COT,COD);
}
void Timer0_Isr(void) interrupt 1
{
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
}
(2)按键检测函数:
#ifndef SIMPLE_DEVICE_H
#define SIMPLE_DEVICE_H
#include "Public.h"
void LED_Show(u8 l_data);
u8 M_key();
#endif
#include "Simple_Device.h"
/*
根据输入的8位数显示LED,其中1为亮灯
*/
void LED_Show(u8 l_data)
{
Select(4,~l_data);
}
/*
矩阵按键检测
*/
u8 M_key()
{
u16 key_temp=0,i=0;
//逐个置零,读取电平
P44=0;P42=1;P35=1;P34=1;
key_temp |= (P3&0x0f);
P44=1;P42=0;P35=1;P34=1;
key_temp = (key_temp<<4) | (P3&0x0f);
P44=1;P42=1;P35=0;P34=1;
key_temp = (key_temp<<4) | (P3&0x0f);
P44=1;P42=1;P35=1;P34=0;
key_temp = (key_temp<<4) | (P3&0x0f);
//检测数据
for(i=0;i<16;i++)
{
if((key_temp & (0x8000>>i)) == 0)
return i+4;
}
return 0;
}
PCF8591:
由于我常常会忘记设备地址、控制字节格式、应答信号,所以我常常会从从官方给的数据中的数据手册中获得信息:
目录:
地址:
命令字节:
应答信号:
数据与电压换算:
(1)主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
#include "PCF8591.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
void Key_Proc();
void SEG_Proc();
void main()
{
Close_All();
Timer0_Init();
//确定输出为AIN3
PCF8591_Write(0x03);
while(1)
{
SEG_Proc();
// Key_Proc();
}
}
void Key_Proc()
{
u8 key_now,key_dwon;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon)
{
sprintf(COT,"%u",(u16)key_dwon);
SEG_TSL(COT,COD);
}
}
void SEG_Proc()
{
u8 show_cot;
if(seg_delay)return;
seg_delay = 1;
show_cot = PCF8591_Read();
sprintf(COT,"%u",(u16)show_cot);
// sprintf(COT,"%u%u",(u16)1234,(u16)5678);
SEG_TSL(COT,COD);
}
void Timer0_Isr(void) interrupt 1
{
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
}
(2)PCF8591函数
#ifndef PCF8591_H
#define PCF8591_H
#include "Public.h"
#include "iic.h"
void PCF8591_Write(u8 c_data);
u8 PCF8591_Read();
#endif
#include "PCF8591.h"
/*
写入控制字节
*/
void PCF8591_Write(u8 c_data)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(c_data);
IIC_WaitAck();
IIC_Stop();
}
/*
读取数据字节
*/
u8 PCF8591_Read()
{
u8 d_data;
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
d_data = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return d_data;
}
(3)官方给的IIC驱动文件:
#ifndef _IIC_H
#define _IIC_H
#include "Public.h"
#include "intrins.h"
sbit SDA = P2^1;
sbit SCL = P2^0;
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);
#endif
#include "iic.h"
#define DELAY_TIME 5
//
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;
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;
}
AT24C02:
设备地址:
写操作:
读操作:
(1)主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
#include "PCF8591.h"
#include "AT24C02.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
void Key_Proc();
void SEG_Proc();
void main()
{
Close_All();
Timer0_Init();
while(1)
{
SEG_Proc();
// Key_Proc();
}
}
void Key_Proc()
{
u8 key_now,key_dwon;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon)
{
sprintf(COT,"%u",(u16)key_dwon);
SEG_TSL(COT,COD);
}
}
void Delay5ms() //@12MHz
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
void SEG_Proc()
{
static u8 num=0;
u8 show_cot;
if(seg_delay)return;
seg_delay = 1;
AT24C02_Write(0x01,num);
Delay5ms();
show_cot = AT24C02_Read(0x01);
sprintf(COT,"%u",(u16)show_cot);
// sprintf(COT,"%u%u",(u16)1234,(u16)5678);
SEG_TSL(COT,COD);
num++;
}
void Timer0_Isr(void) interrupt 1
{
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
}
(2)AT24C02函数:
#ifndef AT24C02_H
#define AT24C02_H
#include "Public.h"
#include "iic.h"
void AT24C02_Write(u8 w_addr,u8 w_data);
u8 AT24C02_Read(u8 r_addr);
#endif
#include "AT24C02.h"
void AT24C02_Write(u8 w_addr,u8 w_data)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(w_addr);
IIC_WaitAck();
IIC_SendByte(w_data);
IIC_WaitAck();
IIC_Stop();
}
u8 AT24C02_Read(u8 r_addr)
{
u8 r_data;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(r_addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
r_data = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return r_data;
}
二、实现功能:
由于我们是靠按键改变模式的,所以我们可以从按键函数出发,补充各种功能。
基本功能框架:
按键可以分为两种:功能按键和切换按键,搭建框架则要抓住切换按键。
由上面两图我们可以知道,显示模式分为非显示模式、设置模式和亮度显示模式,其中设置模式又分为三种状态。
(1)部分主函数:
void main()
{
Close_All();
Timer0_Init();
while(1)
{
// SEG_Proc();
Key_Proc();
LED_Show(0x01<<(set_mode+5));
}
}
void Key_Proc()
{
u8 key_now,key_dwon,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_up = ~key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 7)
{
}
else if(key_dwon == 6)
{
if(++set_mode == 3)set_mode = 0;
LED_Show(0x01<<(set_mode+5));
}
else if(key_dwon == 5)
{
}
else if(key_dwon == 4)
{
if(set_mode == 0)
{
seg_mode = 1;
LED_Show(seg_mode);
}
}
else if(key_up == 4)
{
if(set_mode == 0)
{
seg_mode = 0;
LED_Show(seg_mode);
}
}
}
非设置模式:
(1)部分主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
#include "PCF8591.h"
#include "AT24C02.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
//模式
u8 seg_mode,set_mode;
//非设置模式
u16 led_time=400,l_count_ms,p_count_ms;
u8 l_data,l_power=1,led_mode,turn_sign=1;
void Key_Proc()
{
u8 key_now,key_dwon,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_up = ~key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 7)
{
turn_sign ^= 1;
}
else if(key_dwon == 6)
{
if(++set_mode == 3)
{
set_mode = 0;
seg_mode = 0;
}
else
seg_mode = 1;
}
else if(key_dwon == 5)
{
}
else if(key_dwon == 4)
{
if(set_mode == 0)
{
seg_mode = 2;
}
}
else if(key_up == 4)
{
if(set_mode == 0)
{
seg_mode = 0;
}
}
}
void SEG_Proc()
{
u8 show_cot;
if(seg_delay)return;
seg_delay = 1;
//非设置模式,数码管不显示任何东西
if(seg_mode == 0)
{
sprintf(COT,"");
PCF8591_Proc();
}
// sprintf(COT,"%u %u",(u16)l_power,(u16)l_temp);
SEG_TSL(COT,COD);
}
void Timer0_Isr(void) interrupt 1
{
l_count_ms++;
p_count_ms++;
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
if(set_mode == 0)
{
if(p_count_ms < 10*0.25*l_power)
LED_Show(l_data);
else
LED_Show(0x00);
if(p_count_ms == 10)
p_count_ms = 0;
}
else
LED_Show(0x00);
}
void LED_Proc()
{
static u8 led_temp;
if(l_count_ms < led_time || !turn_sign )return;
l_count_ms = 0;
if(led_mode == 0)
{
l_data = 0x01<<led_temp;
led_temp++;
if(led_temp == 8)
{
led_temp = 0;
led_mode = 1;
}
}
else if(led_mode == 1)
{
l_data = 0x80>>led_temp;
led_temp++;
if(led_temp == 8)
{
led_temp = 0;
led_mode = 2;
}
}
else if(led_mode == 2)
{
l_data = (0x80>>led_temp) | (0x01<<led_temp);
led_temp++;
if(led_temp == 4)
{
led_temp = 0;
led_mode = 3;
}
}
else if(led_mode == 3)
{
l_data = (0x08>>led_temp) | (0x10<<led_temp);
led_temp++;
if(led_temp == 4)
{
led_temp = 0;
led_mode = 0;
}
}
}
亮度显示模式:
(1)部分主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
#include "PCF8591.h"
#include "AT24C02.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
//模式
u8 seg_mode,set_mode;
//非设置模式
u16 led_time=400,l_count_ms,p_count_ms;
u8 l_data,l_power=1,led_mode,turn_sign=1;
void Key_Proc()
{
u8 key_now,key_dwon,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_up = (~key_now) & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 7)
{
turn_sign ^= 1;
}
else if(key_dwon == 6)
{
if(++set_mode == 3)
{
set_mode = 0;
seg_mode = 0;
}
else
seg_mode = 1;
}
else if(key_dwon == 5)
{
}
else if(key_dwon == 4)
{
if(seg_mode == 0)
{
seg_mode = 2;
}
}
else if(key_up == 4)
{
if(seg_mode == 2)
{
seg_mode = 0;
}
}
}
void SEG_Proc()
{
u8 show_cot;
if(seg_delay)return;
seg_delay = 1;
//非设置模式,数码管不显示任何东西
if(seg_mode == 0)
{
sprintf(COT," ");
}
if(seg_mode == 2)
{
sprintf(COT," %02u",(u16)l_power);
}
// sprintf(COT,"%u %u",(u16)l_power,(u16)l_temp);
SEG_TSL(COT,COD);
}
void Timer0_Isr(void) interrupt 1
{
l_count_ms++;
p_count_ms++;
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
if(set_mode == 0)
{
PCF8591_Proc();
if(p_count_ms < 10*0.25*l_power)
LED_Show(l_data);
else
LED_Show(0x00);
if(p_count_ms == 10)
p_count_ms = 0;
}
else
LED_Show(0x00);
}
void LED_Proc()
{
static u8 led_temp;
if(l_count_ms < led_time || !turn_sign )return;
l_count_ms = 0;
if(led_mode == 0)
{
l_data = 0x01<<led_temp;
led_temp++;
if(led_temp == 8)
{
led_temp = 0;
led_mode = 1;
}
}
else if(led_mode == 1)
{
l_data = 0x80>>led_temp;
led_temp++;
if(led_temp == 8)
{
led_temp = 0;
led_mode = 2;
}
}
else if(led_mode == 2)
{
l_data = (0x80>>led_temp) | (0x01<<led_temp);
led_temp++;
if(led_temp == 4)
{
led_temp = 0;
led_mode = 3;
}
}
else if(led_mode == 3)
{
l_data = (0x08>>led_temp) | (0x10<<led_temp);
led_temp++;
if(led_temp == 4)
{
led_temp = 0;
led_mode = 0;
}
}
}
设置模式:
(1)部分主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
#include "PCF8591.h"
#include "AT24C02.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
//模式
u8 seg_mode,set_mode;
//非设置模式
u16 led_time=400,l_count_ms,p_count_ms;
u8 l_data,l_power=1,led_mode=1,turn_sign=1;
u8 flash_sign , led_temp;
void Key_Proc()
{
u8 key_now,key_dwon,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_up = (~key_now) & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 7)
{
turn_sign ^= 1;
}
else if(key_dwon == 6)
{
if(++set_mode == 3)
{
set_mode = 0;
seg_mode = 0;
//重新计数
l_count_ms = 0;
p_count_ms = 0;
//闪烁标志更新
flash_sign = 0;
l_data = 0;
led_temp = 0;
}
else
seg_mode = 1;
}
else if(key_dwon == 5)
{
switch(set_mode)
{
case 1:led_mode++;
break;
case 2:led_time+=100;
break;
}
//上边界属性
if(led_mode == 5)led_mode = 1;
if(led_time == 1300)led_time = 400;
}
else if(key_dwon == 4)
{
if(seg_mode == 0)
{
seg_mode = 2;
}
switch(set_mode)
{
case 1:led_mode--;
break;
case 2:led_time-=100;
break;
}
//下边界属性
if(led_mode == 0)led_mode = 4;
if(led_time == 300)led_time = 1200;
}
else if(key_up == 4)
{
if(seg_mode == 2)
{
seg_mode = 0;
}
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
//非设置模式,数码管不显示任何东西
if(seg_mode == 0)
{
sprintf(COT," ");
}
if(seg_mode == 1)
{
if(set_mode == 1 && flash_sign == 1)
{
sprintf(COT," %4u",(u16)led_time);
flash_sign = 0;
}
else if(set_mode == 2 && flash_sign == 1)
{
sprintf(COT,"0%1u0 ",(u16)led_mode);
flash_sign = 0;
}
else
{
sprintf(COT,"0%1u0 %4u",(u16)led_mode,(u16)led_time);
flash_sign = 1;
}
}
if(seg_mode == 2)
{
sprintf(COT," %02u",(u16)l_power);
}
SEG_TSL(COT,COD);
}
补充:(忘记实现AT24C02功能)
void main()
{
Close_All();
Timer0_Init();
//选择AIN3输出
PCF8591_Write(0x03);
AT24C02_Proc();
while(1)
{
SEG_Proc();
Key_Proc();
LED_Proc();
}
}
void Key_Proc()
{
u8 key_now,key_dwon,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_up = (~key_now) & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 7)
{
turn_sign ^= 1;
}
else if(key_dwon == 6)
{
if(++set_mode == 3)
{
set_mode = 0;
seg_mode = 0;
//重新计数
l_count_ms = 0;
p_count_ms = 0;
//闪烁标志更新
flash_sign = 0;
l_data = 0;
led_temp = 0;
//保存信息到EEPROM
at24_data[0] = led_mode;
at24_data[1] = led_time>>8;//高八位
at24_data[2] = led_time&0x00ff;//低八位
AT24C02_Write(0x01,at24_data,3);
}
else
seg_mode = 1;
}
else if(key_dwon == 5)
{
switch(set_mode)
{
case 1:led_mode++;
break;
case 2:led_time+=100;
break;
}
//上边界属性
if(led_mode >= 5)led_mode = 1;
if(led_time >= 1300)led_time = 400;
}
else if(key_dwon == 4)
{
if(seg_mode == 0)
{
seg_mode = 2;
}
switch(set_mode)
{
case 1:led_mode--;
break;
case 2:led_time-=100;
break;
}
//下边界属性
if(led_mode <= 0)led_mode = 4;
if(led_time <= 300)led_time = 1200;
}
else if(key_up == 4)
{
if(seg_mode == 2)
{
seg_mode = 0;
}
}
}
void AT24C02_Proc()
{
AT24C02_Read(0x01,at24_data,3);
led_mode = at24_data[0];
led_time = ((at24_data[1]<<8) | at24_data[2]);
}
三、参考代码:
主函数:
#include "Public.h"
#include "Simple_Device.h"
#include "timer.h"
#include "stdio.h"
#include "SEG.h"
#include "PCF8591.h"
#include "AT24C02.h"
u8 key_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PIS;
//模式
u8 seg_mode,set_mode;
//非设置模式
u16 led_time=400,l_count_ms,p_count_ms;
u8 l_data,l_power=1,led_mode=1,turn_sign=1;
u8 flash_sign , led_temp;
//EEPROM
u8 at24_data[3];
void Key_Proc();
void SEG_Proc();
void LED_Proc();
void PCF8591_Proc();
void AT24C02_Proc();
void main()
{
Close_All();
Timer0_Init();
//选择AIN3输出
PCF8591_Write(0x03);
AT24C02_Proc();
while(1)
{
SEG_Proc();
Key_Proc();
LED_Proc();
}
}
void Key_Proc()
{
u8 key_now,key_dwon,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_dwon = key_now & (key_now ^ key_old);
key_up = (~key_now) & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 7)
{
turn_sign ^= 1;
}
else if(key_dwon == 6)
{
if(++set_mode == 3)
{
set_mode = 0;
seg_mode = 0;
//重新计数
l_count_ms = 0;
p_count_ms = 0;
//闪烁标志更新
flash_sign = 0;
l_data = 0;
led_temp = 0;
//保存信息到EEPROM
at24_data[0] = led_mode;
at24_data[1] = led_time>>8;//高八位
at24_data[2] = led_time&0x00ff;//低八位
AT24C02_Write(0x01,at24_data,3);
}
else
seg_mode = 1;
}
else if(key_dwon == 5)
{
switch(set_mode)
{
case 1:led_mode++;
break;
case 2:led_time+=100;
break;
}
//上边界属性
if(led_mode >= 5)led_mode = 1;
if(led_time >= 1300)led_time = 400;
}
else if(key_dwon == 4)
{
if(seg_mode == 0)
{
seg_mode = 2;
}
switch(set_mode)
{
case 1:led_mode--;
break;
case 2:led_time-=100;
break;
}
//下边界属性
if(led_mode <= 0)led_mode = 4;
if(led_time <= 300)led_time = 1200;
}
else if(key_up == 4)
{
if(seg_mode == 2)
{
seg_mode = 0;
}
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
//非设置模式,数码管不显示任何东西
if(seg_mode == 0)
{
sprintf(COT," ");
}
if(seg_mode == 1)
{
if(set_mode == 1 && flash_sign == 1)
{
sprintf(COT," %4u",(u16)led_time);
flash_sign = 0;
}
else if(set_mode == 2 && flash_sign == 1)
{
sprintf(COT,"0%1u0 ",(u16)led_mode);
flash_sign = 0;
}
else
{
sprintf(COT,"0%1u0 %4u",(u16)led_mode,(u16)led_time);
flash_sign = 1;
}
}
if(seg_mode == 2)
{
sprintf(COT," %02u",(u16)l_power);
}
SEG_TSL(COT,COD);
}
void Timer0_Isr(void) interrupt 1
{
l_count_ms++;
p_count_ms++;
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 800)seg_delay = 0;
SEG_Show(COD[PIS],PIS);
if(++PIS == 8)PIS = 0;
if(set_mode == 0)
{
if(p_count_ms < 10*0.25*l_power)
LED_Show(l_data);
else
LED_Show(0x00);
if(p_count_ms == 10)
p_count_ms = 0;
}
else
LED_Show(0x00);
}
void LED_Proc()
{
if(l_count_ms < led_time || !turn_sign )return;
l_count_ms = 0;
PCF8591_Proc();
if(led_mode == 1)
{
l_data = 0x01<<led_temp;
led_temp++;
if(led_temp == 8)
{
led_temp = 0;
}
}
else if(led_mode == 2)
{
l_data = 0x80>>led_temp;
led_temp++;
if(led_temp == 8)
{
led_temp = 0;
}
}
else if(led_mode == 3)
{
l_data = (0x80>>led_temp) | (0x01<<led_temp);
led_temp++;
if(led_temp == 4)
{
led_temp = 0;
}
}
else if(led_mode == 4)
{
l_data = (0x08>>led_temp) | (0x10<<led_temp);
led_temp++;
if(led_temp == 4)
{
led_temp = 0;
}
}
}
void PCF8591_Proc()
{
float pcf_data=0,i=0;
pcf_data = PCF8591_Read()/256.0*5;
for(i=0;i<4;i++)
if(pcf_data<=1.6*i)
{
l_power = i+1;
return;
}
}
void AT24C02_Proc()
{
AT24C02_Read(0x01,at24_data,3);
led_mode = at24_data[0];
led_time = ((at24_data[1]<<8) | at24_data[2]);
}
公共函数:
#ifndef PBBLIC_H
#define PBBLIC_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void Close_All();
void Select(u8 cs,u8 s_data);
#endif
#include "Public.h"
/*
向某个锁存器发送信息
*/
void Select(u8 cs,u8 s_data)
{
P0 = s_data;
P2 = P2 & 0x1f | (cs<<5);
P2 &= 0x1f;
}
/*
关闭无关设备
*/
void Close_All()
{
//关闭蜂鸣器和继电器
Select(5,0x00);
//关闭LED
Select(4,0xff);
//清空数码管数据
Select(7,0xff);
}
简单外设:
#ifndef SIMPLE_DEVICE_H
#define SIMPLE_DEVICE_H
#include "Public.h"
void LED_Show(u8 l_data);
u8 M_key();
#endif
#include "Simple_Device.h"
/*
根据输入的8位数显示LED,其中1为亮灯
*/
void LED_Show(u8 l_data)
{
Select(4,~l_data);
}
/*
矩阵按键检测
*/
u8 M_key()
{
u16 key_temp=0,i=0;
//逐个置零,读取电平
P44=0;P42=1;P35=1;P34=1;
key_temp |= (P3&0x0f);
P44=1;P42=0;P35=1;P34=1;
key_temp = (key_temp<<4) | (P3&0x0f);
P44=1;P42=1;P35=0;P34=1;
key_temp = (key_temp<<4) | (P3&0x0f);
P44=1;P42=1;P35=1;P34=0;
key_temp = (key_temp<<4) | (P3&0x0f);
//检测数据
for(i=0;i<16;i++)
{
if((key_temp & (0x8000>>i)) == 0)
return i+4;
}
return 0;
}
定时器
#ifndef TIME_H
#define TIME_H
#include "Public.h"
void Timer0_Init(void);
#endif
#include "timer.h"
void Timer0_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}
数码管:
#ifndef SEG_H
#define SEG_H
#include "Public.h"
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 COD,u8 PIS);
#endif
#include "SEG.h"
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
/*
输入字符串输出数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0;
for(i=0;i<8;i++)
{
switch(input[i])
{
case '0':output[i] = Seg_Table[0];break;
case '1':output[i] = Seg_Table[1];break;
case '2':output[i] = Seg_Table[2];break;
case '3':output[i] = Seg_Table[3];break;
case '4':output[i] = Seg_Table[4];break;
case '5':output[i] = Seg_Table[5];break;
case '6':output[i] = Seg_Table[6];break;
case '7':output[i] = Seg_Table[7];break;
case '8':output[i] = Seg_Table[8];break;
case '9':output[i] = Seg_Table[9];break;
default:output[i] = 0xff;
}
}
}
/*
数码管显示函数
*/
void SEG_Show(u8 COD,u8 PIS)
{
//消隐
Select(7,0xff);
//位选
Select(6,0x01<<PIS);
//段选
Select(7,COD);
}
PCF8591:
#ifndef PCF8591_H
#define PCF8591_H
#include "Public.h"
#include "iic.h"
void PCF8591_Write(u8 c_data);
u8 PCF8591_Read();
#endif
#include "PCF8591.h"
/*
写入控制字节
*/
void PCF8591_Write(u8 c_data)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(c_data);
IIC_WaitAck();
IIC_Stop();
}
/*
读取数据字节
*/
u8 PCF8591_Read()
{
u8 d_data;
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
d_data = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return d_data;
}
AT24C02:
#ifndef AT24C02_H
#define AT24C02_H
#include "Public.h"
#include "iic.h"
void AT24C02_Write(u8 w_addr,u8 *w_data,u8 num);
void AT24C02_Read(u8 r_addr,u8 *r_data,u8 num);
void AT24C02_Write1(u8 w_addr,u8 w_data);
u8 AT24C02_Read1(u8 r_addr);
void Delay5ms() ;
#endif
#include "AT24C02.h"
void Delay5ms() //@12MHz
{
unsigned char i, j;
i = 59;
j = 90;
do
{
while (--j);
} while (--i);
}
void AT24C02_Write(u8 w_addr,u8 *w_data,u8 num)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(w_addr);
IIC_WaitAck();
while(num--)
{
IIC_SendByte(*w_data);
w_data++;
IIC_WaitAck();
Delay5ms();
}
IIC_Stop();
}
void AT24C02_Read(u8 r_addr,u8 *r_data,u8 num)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(r_addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
while(num--)
{
*r_data = IIC_RecByte();
r_data++;
if(num == 0)
IIC_SendAck(1);
else
IIC_SendAck(0);
}
IIC_Stop();
}
IIC
#ifndef _IIC_H
#define _IIC_H
#include "Public.h"
#include "intrins.h"
sbit SDA = P2^1;
sbit SCL = P2^0;
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);
void IIC_Delay(unsigned char i);
#endif
#include "iic.h"
#define DELAY_TIME 5
//
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;
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;
}
四、收获:
利用STC-ISP初始化定时器时要注意开中断
初始化模块的时候最好先初始化数码管
IIC写一次时间大概要5ms,不能刚进行写操作后就进行读操作,在测试模块时要着重注意
重新设置模式时记得重新计数
5、做完后记得检查有没有模块没用,有没有功能没实现