2019年3月12日更新
在连续多次单字节读取E22PROM时,不需要延时。
搞完所有模块,开始写真题。
1、题目解读
看到这个题,大致要知道用到了哪些模块。
LED、数码管、AD、E2PROM、独立按键。
2、代码
在这里我直接把所有代码给贴上来吧,程序可能写的很麻烦,大家参考一下就行了
也可以在这下载https://download.csdn.net/download/xiaomo_haa/10991680
main.c
#include <stc15.h>
#include "sys.h"
u8 time_led[] = {0x11, 0x04, 0x04, 0x04, 0x04}; //LED流转间隔 *100
u8 Mode_led = 1;
u8 pwm = 4;
u8 Mode_Option = 0; //设置模式位 0无/1流转方式/2流转间隔
u8 led_lighting = 0; //LED亮度
bit flag_led = 0; //LED工作标志
bit flag_800ms = 1;
bit display_pwm = 0;
void main(void)
{
u8 flag_dat = 0;
All_init();
Timer0Init();
Timer1Init();
flag_dat = Read_E2PROM(0x00); //读取E2PROM写入标志位
if(flag_dat == 0x11)
{
time_led[0] = flag_dat;
time_led[1] = Read_E2PROM(0x01);
time_led[2] = Read_E2PROM(0x02);
time_led[3] = Read_E2PROM(0x03);
time_led[4] = Read_E2PROM(0x04);
}
LED_work(0xff);
EA = 1;
while(1)
{
Key_press();
}
}
sys.c
#include "sys.h"
void All_init(void)
{
P2 = (P2 & 0x1f) | 0x80; //打开Y4C
P0 = 0xff; //关闭LED
P2 = (P2 & 0x1f) | 0xc0; //打开Y6C
P0 = 0x00; //关闭所有数码管
P2 = (P2 & 0x1f) | 0xa0; //打开Y5C
P0 = 0x00; //关闭蜂鸣器和继电器
P2 = P2 & 0x1f; //关闭所有573
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9a; //设置定时初值
TH0 = 0xa9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
}
void Timer0(void) interrupt 1
{
static u16 T0count1 = 0, T0count2 = 0;
static u8 index = 0, e2_addr = 0x00;
T0count2 ++;
if(Mode_Option > 0) //800ms数码管闪烁
{
T0count1 ++;
if(T0count1 >= 400)
{
T0count1 = 0;
flag_800ms = ~flag_800ms;
}
}
if((T0count2 % 5 == 0) && (T0count2 < 30)) //每10ms时写一次E2PROM
{
switch(index)
{
case 0: Write_E2PROM(0x00, time_led[e2_addr]); break;
case 1: Write_E2PROM(0x01, time_led[e2_addr]); break;
case 2: Write_E2PROM(0x02, time_led[e2_addr]); break;
case 3: Write_E2PROM(0x03, time_led[e2_addr]); break;
case 4: Write_E2PROM(0x04, time_led[e2_addr]); break;
default : break;
}
index ++;
e2_addr ++;
if(index >= 5)
{
index = 0;
e2_addr = 0;
}
}
else if(T0count2 >= 30) //60ms时读取一次AD值
{
T0count2 = 0;
pwm = Read_AIN(0x03);
}
Key_Scan();
Smg_show();
Smg_Scan();
}
void Timer1Init(void) //100us@11.0592MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xAE; //设置定时初值
TH1 = 0xFB; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1暂停计时
ET1 = 1;
}
void Timer1(void) interrupt 3
{
static u8 dat;
static u16 T1count1 = 0;
static u8 mode_backup = 0;
static u8 index = 0, T1count2 = 0;
static u8 mode_index = 1;
u16 temp = 0;
u8 hightime = 0;
T1count1 ++;
T1count2 ++;
T1count2 &= 0x0f; //最大计数到15
temp = 1000 * time_led[mode_index]; //流转时间间隔
hightime = pwm * pwm; //高电平时间
if(T1count1 >= temp)
{
T1count1 = 0;
if(mode_index == 1)
{
if(mode_backup != mode_index)
{
dat = 0x7f;
mode_backup = mode_index;
}
dat = _crol_(dat, 1); //模式1
if(dat == 0x7f)
mode_index ++;
}
else if(mode_index == 2)
{
if(mode_backup != mode_index)
{
dat = 0xfe;
mode_backup = mode_index;
}
dat = _cror_(dat, 1); //模式2
if(dat == 0xfe)
mode_index ++;
}
else if(mode_index == 3)
{
if(mode_backup != mode_index)
{
index = 0;
mode_backup = mode_index;
}
switch(index)
{
case 0: dat = 0x7e; break; //0111 1110
case 1: dat = 0xbd; break; //1011 1101
case 2: dat = 0xdb; break;
case 3: dat = 0xe7; break;
default : break;
}
index ++;
index &= 0x03;
if(dat == 0xe7)
mode_index ++;
}
else if(mode_index == 4)
{
if(mode_backup != mode_index)
{
index = 0;
mode_backup = mode_index;
}
switch(index)
{
case 0: dat = 0xe7; break; //1110 0111
case 1: dat = 0xdb; break; //1011 1101
case 2: dat = 0xbd; break;
case 3: dat = 0x7e; break;
default : break;
}
index ++;
index &= 0x03;
if(dat == 0x7e)
mode_index = 1;
}
}
if(T1count2 < hightime) //PWM
LED_work(dat);
else
LED_work(0xff);
}
sys.h
#ifndef _SYS_H_
#define _SYS_H_
//头文件包含
#include <stc15.h>
#include <intrins.h>
#include "iic.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
//外部变量
extern u8 time_led[]; //LED流转间隔 *100
extern u8 Mode_led;
extern u8 pwm;
extern u8 Mode_Option; //设置模式位 0无/1流转方式/2流转间隔
extern u8 led_lighting; //LED亮度
extern bit flag_led; //LED工作标志
extern bit flag_800ms;
extern bit display_pwm;
extern u8 KeySta[]; //键值存储区
extern u8 Keybackup[];
//管脚定义
//函数声明
void All_init(void);
void Timer0Init(void);
void Timer1Init(void);
void Smg_Scan(void);
void Smg_show();
void Smg_show();
void LED_work(u8 dat);
void Key_Scan(void);
void Key_drive(u8 key);
void Key_press(void);
#endif
key.c
#include "sys.h"
u8 KeySta[] = {1, 1, 1, 1}; //键值存储区
u8 Keybackup[] = {1, 1, 1, 1}; //键值备份区
sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
sbit S7 = P3^0;
//按键扫描函数,在定时器中断里调用
void Key_Scan(void)
{
static u8 Keybuff[] = {0xff, 0xff, 0xff, 0xff}; //按键缓冲区
u8 i = 0;
Keybuff[0] = (Keybuff[0] << 1) | S7;
Keybuff[1] = (Keybuff[1] << 1) | S6;
Keybuff[2] = (Keybuff[2] << 1) | S5;
Keybuff[3] = (Keybuff[3] << 1) | S4;
for(i = 0; i < 4; i++)
{
if(Keybuff[i] == 0xff) //按键松开
KeySta[i] = 1;
else if(Keybuff[i] == 0x00) //按键按下
KeySta[i] = 0;
else //键值不稳定
{}
}
}
void Key_drive(u8 key)
{
if(key == 0)
{
if(TR1 == 0)
TR1 = 1;
else
TR1 = 0;
}
else if(key == 1)
{
Mode_Option ++;
if(Mode_Option >= 3)
Mode_Option = 0;
}
else if(key == 2)
{
if(Mode_Option == 1)
{
Mode_led ++;
if(Mode_led >= 4) //模式最大4
Mode_led = 4;
}
else if(Mode_Option == 2)
{
time_led[Mode_led] ++;
if(time_led[Mode_led] >= 12) //最大1200ms
time_led[Mode_led] = 12;
}
}
else if(key == 3)
{
if(Mode_Option == 1)
{
Mode_led --;
if(Mode_led <= 1) //模式最小1
Mode_led = 1;
}
else if(Mode_Option == 2)
{
time_led[Mode_led] --;
if(time_led[Mode_led] <= 4) //最小400ms
time_led[Mode_led] = 4;
}
}
}
//检测按键是否按下,在main函数调用
void Key_press(void)
{
u8 i;
for(i = 0; i < 4; i ++)
{
if(KeySta[i] != Keybackup[i])
{
if(Keybackup[i] != 0) //按键松开时操作
Key_drive(i);
Keybackup[i] = KeySta[i];
}
}
if(Mode_Option == 0)
{
if(KeySta[3] == 0)
display_pwm = 1;
else
display_pwm = 0;
}
}
display.c
#include "sys.h"
u8 code Nixie[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
0xff, 0xbf}; //16 17
u8 Nixiebuff[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 smg1, smg2, smg3, smg4, smg5, smg6, smg7, smg8;
//数码管扫描
void Smg_Scan(void)
{
static u8 index = 0;
P2 = (P2 & 0x1f) | 0xc0; //打开Y6C
P0 = 0x01 << index;
P2 = (P2 & 0x1f) | 0xe0; //打开Y7C
P0 = 0xff;
P0 = Nixiebuff[index];
index ++;
index &= 0x07;
}
//更新数码管值
void Smg_show()
{
if(Mode_Option == 0) //不是设置模式不显示
{
if(display_pwm == 0)
smg1 = smg2 = smg3 = smg4 = smg5 = smg6 = smg7 = smg8 = 16;
else
{
smg1 = smg2 = smg3 = smg4 = smg5 = smg6 = 16;
smg7 = 17;
smg8 = pwm % 10;
}
}
else if(Mode_Option == 1)
{
if(flag_800ms == 1) //显示
{
smg1 = 17;
smg2 = Mode_led % 10;
smg3 = 17;
smg4 = 16;
smg5 = time_led[Mode_led] / 10;
smg6 = time_led[Mode_led] % 10;
smg7 = 0;
smg8 = 0;
}
else //不显示,实现闪烁
{
smg1 = 16;
smg2 = 16;
smg3 = 16;
smg4 = 16;
smg5 = time_led[Mode_led] / 10;
smg6 = time_led[Mode_led] % 10;
smg7 = 0;
smg8 = 0;
}
}
else if(Mode_Option == 2)
{
if(flag_800ms == 1) //显示
{
smg1 = 17;
smg2 = Mode_led % 10;
smg3 = 17;
smg4 = 16;
smg5 = time_led[Mode_led] / 10;
smg6 = time_led[Mode_led] % 10;
smg7 = 0;
smg8 = 0;
}
else //不显示,实现闪烁
{
smg1 = 17;
smg2 = Mode_led % 10;
smg3 = 17;
smg4 = 16;
smg5 = 16;
smg6 = 16;
smg7 = 16;
smg8 = 16;
}
}
Nixiebuff[0] = Nixie[smg1];
Nixiebuff[1] = Nixie[smg2];
Nixiebuff[2] = Nixie[smg3];
Nixiebuff[3] = Nixie[smg4];
Nixiebuff[4] = Nixie[smg5];
Nixiebuff[5] = Nixie[smg6];
Nixiebuff[6] = Nixie[smg7];
Nixiebuff[7] = Nixie[smg8];
}
//LED显示
void LED_work(u8 dat)
{
P2 = (P2 & 0x1f) | 0x80;
P0 = dat;
P2 = P2 & 0x1f;
}
iic.c
#include "sys.h"
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
//应答位控制
void IIC_Ack(bit ackbit)
{
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
/*******************************************************************************
* 函数名 :Read_AIN
* 输入值 :unsigned char chn
* 返回值 :unsigend char dat
* 作者 :小默haa
* 时间 :2019年2月25日
* 功能描述:读取PCF8591AIN采集数据
* 备注 :chn为PCF8591的通道
*******************************************************************************/
unsigned char Read_AIN(unsigned char chn)
{
unsigned char dat, val, ad_pwm;
EA = 0;
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x90); //PCF8591的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(chn); //写入PCF8591的控制字节
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //IIC总线停止信号
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x91); //PCF8591的读设备地址
IIC_WaitAck(); //等待从机应答
dat = IIC_RecByte(); //读取PCF8591通道3的数据
IIC_Ack(0); //产生非应答信号
IIC_Stop(); //IIC总线停止信号
val = (dat * 50) / 255;
if((val >= 38) && (val <= 50))
ad_pwm = 4;
else if((val >= 26) && (val < 38))
ad_pwm = 3;
else if((val >= 14) && (val < 26))
ad_pwm = 2;
else if((val >= 0) && (val < 14))
ad_pwm = 1;
EA = 1;
return ad_pwm;
}
void Write_E2PROM(unsigned char add, unsigned char dat)
{
EA = 0;
IIC_Start();
IIC_SendByte(0xa0); //发送器件地址
IIC_WaitAck();
IIC_SendByte(add); //发送操作地址
IIC_WaitAck();
IIC_SendByte(dat); //写一字节
IIC_WaitAck();
IIC_Stop();
somenop;
EA = 1;
}
unsigned char Read_E2PROM(unsigned char add)
{
unsigned char d;
IIC_Start();
IIC_SendByte(0xa0); //发送器件地址
IIC_WaitAck();
IIC_SendByte(add); //发送要操作的地址
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xa1); //发送读操作
IIC_WaitAck();
d = IIC_RecByte(); //读一字节
IIC_Ack(0);
IIC_Stop();
return d;
}
iic.h
#ifndef _IIC_H
#define _IIC_H
//函数声明
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(bit ackbit);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
unsigned char Read_AIN(unsigned char chn);
void Write_E2PROM(unsigned char add, unsigned char dat);
unsigned char Read_E2PROM(unsigned char add);
#endif