本次培训内容学iic,要求实现:
????????开机显示光敏电阻的值,S4按键控制显示光敏电阻值,S5按键控制显示Rb2电位器的值,S8按键控制存数据进EEPROM,S9按键控制显示存入EEPROM的值。
代码如下:
具体原理可以参考教程:
蓝桥杯单片机比赛学习(全)_哔哩哔哩_bilibili
//main.c
#include "sys.h"
#include "iic.h"
u16 count=0;
u8 key_temp=0;
u8 key_recall=0;//保留上一个按键的状态
u16 adc_val=0;
u8 flag=0;
u16 erom=255;
u8 s=0;
/*
本次作业:
开机显示光敏电阻的值,S4按键控制显示光敏电阻值,
S5按键控制显示Rb2电位器的值,
S8按键控制存数据进EEPROM,S9按键控制显示存入EEPROM的值。
*/
void delay5ms()
{
unsigned char i,j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void main(){
stop_all();//关蜂鸣器等无关外设
Timer0Init();
write_DAC(erom);//默认写入
while(1){
key_temp=key_scan();
if(key_temp>0){
key_recall=key_temp;
}
DT[4]=key_recall;
if(!flag){//默认显示光感
adc_val=ReadADC(0x01);//0x01 光敏传感
smg_play(adc_val,1);
}
else if(flag==1){
adc_val=ReadADC(0x03);//0x01 光敏传感
smg_play(adc_val,1);
}
smg_play(erom,0);
switch(key_recall){
case(4)://s4显示光敏电阻
flag=0;
break;
case(5)://s5显示Rb2电位器
flag=1;
break;
default:
break;
}
if(key_temp==8){
AT24C02_WB(1,adc_val);delay5ms();//存当前值 延迟保证已写入epprom
}
else if(key_temp==9){
erom=AT24C02_RB(1);delay5ms();
}
}
}
void Time0() interrupt 1{
count++;
if(count==6000){
count=0;
}
smg_show(DT[s],s);//段,位 3 1 10 2
if(++s==10){
s=0;
}
}
//sys.c
#include "sys.h"
sbit buzzer=P0^6;
sbit rely=P0^4;
unsigned char code smg_index[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x7f,0xbf};
u8 DT[]={10,10,10,10,10,10,10,10,10,10,10};
/*
关蜂鸣器,led,继电器,数码管段,位
*/
#define key_low 0x0f
#define key_high 0xf0
//u8 key_press=0;
void stop_all(){
P0=0xff;
P2=P2&0x1f|0x80;
P2&=0x1f;
P0=0;
P2=P2&0x1f|0xe0;
P2&=0x1f;
P2=P2&0x1f|0xc0;
P0=0;
P2&=0x1f;
P2=P2&0x1f|0xa0;
P04=0;
P06=0;
P2&=0x1f;
}
/*
数码管显示
*/
void smg_show(unsigned char du,unsigned char wei){// DT[S] s
P0=1<<wei;
P2=(P2&0x1f)|0xc0;//位选
P2=P2&0x1f;
P0=smg_index[du]; //段选
P2=(P2&0x1f)|0xe0;
P2=P2&0x1f;
}
void Timer0Init(void) //100微秒@11.0592MHz 1ms
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;//开启时钟
}
u8 key_scan(){
static key_state=0,key_return=0; //每次返回值和状态进来不会重置
u8 key_press;
switch(key_state)
{
case 0: //未按按键时的状态
key_return=0; //返回值置零
P3=0x0f; P42=0; P44=0;
//key_return=0;
key_press = P3&key_low;
if(key_press != 0x0f)
key_state=1;
break;
case 1: //按键按下去后第一次进scan_key的状态,每按一次按键只会进来case 1一次
P3=0x0f; P42=0; P44=0;
key_press = P3&key_low;
if(key_press != 0x0f)
{
if(key_press==0x0e) key_return=7;
if(key_press==0x0d) key_return=6;
if(key_press==0x0b) key_return=5;
if(key_press==0x07) key_return=4;
P3=0xf0; P42=1; P44=1;
key_press = P3&key_high;
if(key_press==0xe0) key_return+=12;
if(key_press==0xd0) key_return+=8;
if(P42==0) key_return+=4;
key_state = 2;
}
break;
case 2: //按键一直按着的状态
P3=0x0f; P42=0; P44=0;
key_press=P3&key_low;
if(key_press == 0x0f) //放开按键后key_state = 0回到case 0
{
key_state = 0;
}
default:
break;
}
return key_return;
}
void smg_play(u8 temp,bit dei){
if(dei){
if(temp>100){
DT[5]=temp/100;
DT[6]=temp/10%10;
DT[7]=temp%10;
}
else if(temp<100){
DT[5]=0;
DT[6]=temp/10;
DT[7]=temp%10;
}
}
else{
if(temp>100){
DT[0]=temp/100;
DT[1]=temp/10%10;
DT[2]=temp%10;
}
else if(temp<100){
DT[0]=0;
DT[1]=temp/10;
DT[2]=temp%10;
}
}
}
//sys.h
#ifndef __SYS_H_
#define __SYS_H_
#include "stc15f2k60s2.h"
typedef unsigned char u8;
typedef unsigned int u16;
u8 DT[];
void smg_show(unsigned char du,unsigned char wei);
void stop_all();
void Timer0Init(void);
u8 key_scan();
void smg_play(u8 temp,bit dei);
#endif
//iic.h
#ifndef _IIC_H
#define _IIC_H
void AT24C02_WB(u8 ward,D);
u8 AT24C02_RB(u8 ward);
u8 ReadADC(u8 ain);
void write_DAC(u8 dat);
#endif
//iic.c
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include "sys.h"
#include "intrins.h"
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
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;
}
//通过I2C总线发送数据
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;
}
//从I2C总线上接收数据
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;
}
//adc读取
u8 ReadADC(u8 ain)
{
u8 Data;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(ain);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
Data=IIC_RecByte();
IIC_Stop();
return Data;
}
//EEPROM 写入
void AT24C02_WB(u8 ward,D)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(ward);
IIC_WaitAck();
IIC_SendByte(D);
IIC_WaitAck();
IIC_Stop();
}
//EEPROM 读取
u8 AT24C02_RB(u8 ward)
{
u8 D;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(ward);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
D=IIC_RecByte();
IIC_Stop();
return D;
}
void write_DAC(u8 dat)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
|