蓝桥杯单片机第14届(满分)
1led.c不需要时序保护
idata unsigned char temp_1 = 0x00;
idata unsigned char temp_old_1 = 0xff;
void Led_Disp(unsigned char *ucLed)
{
unsigned char temp;
temp_1=0x00;
temp_1 = (ucLed[0] << 0) | (ucLed[1] << 1) | (ucLed[2] << 2) | (ucLed[3] << 3) |
(ucLed[4] << 4) | (ucLed[5] << 5) | (ucLed[6] << 6) | (ucLed[7] << 7);
if (temp_1 != temp_old_1)
{
P0 = ~temp_1;
// 操作P2锁存器
temp = P2 & 0x1f; // 保留P2的低5位
temp = temp | 0x80; // 与0x80进行或操作
P2 = temp; // 写入P2
temp = P2 & 0x1f; // 保留P2的低5位
P2 = temp; // 写入P2,关闭锁存器
temp_old_1 = temp_1;
}
}
判断一个函数要不要加 EA=0/1 时序保护,唯一的标准是:这个函数是在哪里被调用的?
-
Led_Disp是在定时器中断T1service()里面调用的。 -
单片机有一个硬件机制:当程序进入中断服务函数时,硬件会自动屏蔽掉同级中断。 也就是说,当代码正在执行中断里的
Led_Disp操作P0和P2时,绝对不可能有另一个定时器中断跑出来打断它。它本身就是“最高优先级”的,所以天生自带保护光环! -
谁才需要加
EA=0/1保护? 是在主循环while(1)里面调用的那些操作了P0和P2的函数! 比如你之前写的Relay()。因为主循环运行级别最低,随时可能被定时器中断(也就是Led_Disp和seg_disp)打断。所以主循环里的Relay必须自己加EA=0; Relay(); EA=1;来防身。
2温度读取/AD转换
算温度 (DS18B20):用 读取值 / 16.0。
算电压 (PCF8591):用 读取值 / 51.0
3iic导致数码管闪烁
-
DELAY_TIME根本不是用来防抖或稳定的! 它是用来控制 I2C 总线通讯速度(SCL 时钟频率)的。 -
当你把
DELAY_TIME设为 10 时,执行一次完整的ad_zhuanhuan,CPU 需要在里面空转等待将近 2 毫秒! -
你在
ad_zhuanhuan里用了EA = 0;和EA = 1;。这意味着全局中断被死死关了近 2 毫秒! -
你的数码管是靠定时器每 1 毫秒刷新一次的。中断被关了 2 毫秒,数码管错过了刷新时机,绝对会严重闪烁、卡顿!
解决办法
将你的 DELAY_TIME 改成官方推荐的极小值。单片机跑到 12MHz 时,延时 1 到 2 就足够满足 PCF8591 的通讯要求了。
把这句:
#define DELAY_TIME 10 // 删掉这个习惯!
改成:
#define DELAY_TIME 1 // 提高I2C速度,解放CPU
改完这一步,I2C 整体耗时会降到两三百微秒,远小于 1ms 的数码管刷新周期,数码管立刻就不闪了!
4硬件冲突引脚共用
在蓝桥杯 CT107D 开发板上:
-
NE555 频率发生器的信号:是通过 J3 跳线帽直接连接到单片机的
P34引脚上的(因为 P34 是单片机 Timer 0 的外部脉冲输入脚 T0)
你看一下你的 key_read() 函数里的这一段:
P44=1;P42=1;P35=1;P34=0; // <--- 罪魁祸首在这里!!!
if(P30==0)temp=19;
if(P31==0)temp=18;
// ...
NE555 正在辛辛苦苦地往 P34 引脚发送高低电平的频率脉冲,但你的 key_read() 却在 while(1) 的主循环里疯狂地执行 P34=0;,强行把 P34 拉低到地 (GND)!
这直接导致单片机和 NE555 发生了“信号打架”,你的程序把 NE555 的脉冲给“捂死”了,定时器 0 自然一个脉冲都数不到,频率永远显示 0!
既然这道题要测频率,就绝对不能让程序主动把 P34 拉低。
所以解决办法极其简单:直接把扫描 P34 列的代码删掉(或注释掉),并保证 P34 始终处于高电平接收输入状态即可!
如果写 0:相当于单片机把引脚接地,NE555发出的信号全被吃掉,测不到频率。
如果写 1:STC15单片机在输出 1 的瞬间,会开启“强推挽”模式(强行拉高电压),这会和NE555输出的低电平发生“短路打架”,直接把波形冲烂,导致测不准。结论:既然用来测频率,P34就只能作为“输入引脚”,我们干脆在按键扫描里假装它不存在。
6ERROR L107: ADDRESS SPACE OVERFLOW
“内存溢出(RAM不够用了)”!
在默认情况下,51单片机的变量都会被存放在一个叫 data 的内存区。这个区只有可怜的 128 个字节!
由于这道题你需要算平均值、历史数据、还有一堆计时器,你定义了:
-
11 个 float 浮点数(每个占 4 字节,共 44 字节)
-
1 个 long int 长整型(占 4 字节)
-
变量总大小直接撑爆了这 128 个字节! 编译器装不下去了,就给你报了
ADDRESS SPACE OVERFLOW(地址空间溢出),并且后面跟了一连串的IGNORED SEGMENT(因为装不下,编译器直接罢工,后面的变量全都忽略了)。
🛠️ 终极解法
STC15 单片机其实并不缺内存(它有额外的 256 字节 idata 区,甚至还有 2048 字节的 xdata 区)。
第一次提交18分
把进入seg_proc()的时间从500ms,变成20ms,就从18分变成85分了
main.c
#include <STC15F2K60S2.H>
#include <seg.h>
#include <key.h>
#include <pcf8591.h>
#include <init.h>
#include <led.h>
#include <ds18b20.h>
#include <ds1302.h>
unsigned char seg_pos;
idata unsigned char seg_buf[8]={10,10,10,10,10,10,10,10};
idata unsigned char seg_point[8]={0,0,0,0,0,0,0,0};
idata unsigned char ucled[8]={0,0,0,0,0,0,0,0};
unsigned int seg_slow_down;
unsigned char segmode;
unsigned char key_slow_down;
unsigned char key_val,key_down,key_old,key_up;
float tem;//温度
float tem_m;
idata unsigned char time[7]={1,0,0};//teme[0]--秒,time[1]--分
idata unsigned char time_chu[3]={0};
unsigned int t1000ms;
idata long int freq;
unsigned char wcan_seg=30;//0-99
unsigned char mode;
bit wuxiao;//wuxiao=1,表示频率不在200-2000hz范围内,是无效数据
float shi;
float shi_m;
unsigned char chu;
float v_zhen;
unsigned char ad_slow_down;
unsigned int t3000ms;
bit dangg,dangg_old,cai,f3s;
//dangg=1,表示暗
idata float tem_sum = 0; // 记录所有采集过的温度总和
idata float tem_ave = 0;
idata float tem_old;
idata float shi_sum=0;
idata float shi_ave=0;
idata float shi_old;
bit seg_t;
unsigned int t2000ms;
bit f2s;
//bit first_ad = 1; // 用于标记是否是上电第一次读取AD
unsigned char t100ms;
bit f100ms;
void key_proc()
{
if(key_slow_down<10)return ;
key_slow_down=0;
key_val=key_read();
key_down=key_val&(key_old^key_val);
key_up=~key_val&(key_old^key_val);
key_old=key_val;
if(seg_t==0)//不是特殊界面
{
if(segmode==1&&mode==2)//时间回显子界面下
{
if(key_down==9)
{
f2s=1;
}
if(key_up==9)
{
f2s=0;
if(t2000ms>2000)//长按s9超过2s
{
tem_sum=0;
tem_ave=0;
shi_sum=0;
shi_ave=0;
tem_m=0;
shi_m=0;
chu=0;
}
}
}
switch(key_down)
{
case 4://界面按键
if(++segmode==3)segmode=0;
if(segmode==1)//进入回显界面
{
mode=0;//温度回显界面
}
break;
case 5://回显按键
if(segmode==1)//回显界面
{
if(++mode==3)mode=0;
}
break;
case 8://++
if(segmode==2)
{
wcan_seg++;
if(wcan_seg>=100)wcan_seg=0;
}
break;
case 9://--
if(segmode==2)//参数界面
{
wcan_seg--;
if(wcan_seg>200)wcan_seg=99;
}
break;
}
}
}
void T1service() interrupt 3
{
seg_slow_down++;
key_slow_down++;
ad_slow_down++;
if(++seg_pos==8)seg_pos=0;
seg_disp(seg_pos,seg_buf[seg_pos],seg_point[seg_pos]);
Led_Disp(ucled);
if(++t100ms==100)
{
t100ms=0;
f100ms^=1;
}
if(f3s==1)
{
if(++t3000ms==3000)
{
t3000ms=0;
f3s=0;//已经3s,可以再次触发
seg_t=0;//返回“原状态”
}
}
if(f2s==1)
{
if(t2000ms<4000)
{
t2000ms++;
//这样最大不会超过4000
}
}
if(++t1000ms==1000)
{
t1000ms=0;
TR0=0;
freq=(TH0<<8)|TL0;
TH0=0;
TL0=0;
TR0=1;
}
}
void seg_proc()
{
if(seg_slow_down<20)return;
seg_slow_down=0;
if(cai==1)//触发一次温度、湿度数据采集功能
{
cai=0;//等待下一次触发
seg_t=1;//采集功能触发后,数码管立刻切换到温湿度界面
f3s=1;//计时3s,防止3s内重复触发
t3000ms=0;
//湿度采集
shi_old=shi;
if(freq>=2000)
{
shi=90;
wuxiao=1;//无效数据
}
else if(freq<=200)
{
shi=10;
wuxiao=1;//无效数据
}
else
{
shi=(80.0/1800)*freq +10 -160.0/18;
wuxiao=0;//有效数据
}
tem_old=tem;
tem=rd_temperature();//采集温度,还要在温湿度界面显示
if(wuxiao==0)//采集到的湿度数据有效
{
//触发次数
chu++;//放在前面,以免使得除数为0
shi_sum+=shi;
shi_ave=shi_sum/(chu*1.0); //平均湿度
if(shi>shi_m)
{
shi_m=shi; //最高湿度
}
tem_sum+=tem;
tem_ave=tem_sum/(chu*1.0); //平均温度
if(tem>tem_m)
{
tem_m=tem;
} //最高温度
//触发时间
time_chu[0]=time[0];
time_chu[1]=time[1];
time_chu[2]=time[2];
}
}
read_rtc(time);
if(seg_t==0)//不是特殊界面
{
switch(segmode)
{
case 0://时间界面
//时
seg_buf[0]=time[2]/16;
seg_buf[1]=time[2]%16;
seg_buf[2]=15;
//分
seg_buf[3]=time[1]/16;
seg_buf[4]=time[1]%16;
seg_buf[5]=15;
//秒
seg_buf[6]=time[0]/16;
seg_buf[7]=time[0]%16;
seg_point[6]=0;
break;
case 1://回显界面
if(mode==0)//温度回显
{
seg_buf[0]=16;//C
seg_buf[1]=10;
//最大温度
seg_buf[2]=(chu==0)?10:(unsigned char )tem_m/10;
seg_buf[3]=(chu==0)?10:(unsigned char )tem_m%10;
seg_buf[4]=(chu==0)?10:15;
//平均温度
seg_buf[5]=(chu==0)?10:(unsigned char )tem_ave/10;
seg_buf[6]=(chu==0)?10:(unsigned char )tem_ave%10;
seg_buf[7]=(chu==0)?10:(unsigned int)(tem_ave*10)%10;
seg_point[6]=(chu==0)?0:1;
}
else if(mode==1)//湿度回显
{
seg_buf[0]=17;//H
seg_buf[1]=10;
//最大湿度
seg_buf[2]=(chu==0)?10:(unsigned char )shi_m/10;
seg_buf[3]=(chu==0)?10:(unsigned char )shi_m%10;
seg_buf[4]=(chu==0)?10:15;
//平均湿度
seg_buf[5]=(chu==0)?10:(unsigned char )shi_ave/10;
seg_buf[6]=(chu==0)?10:(unsigned char )shi_ave%10;
seg_buf[7]=(chu==0)?10:(unsigned int)(shi_ave*10)%10;
seg_point[6]=(chu==0)?0:1;
}
else if(mode==2)//时间回显
{
seg_buf[0]=14;//F
//触发次数,长度不足2位时左侧补0
seg_buf[1]=chu/10;
seg_buf[2]=chu%10;
//时
seg_buf[3]=(chu==0)?10:time_chu[2]/16;
seg_buf[4]=(chu==0)?10:time_chu[2]%16;
seg_buf[5]=(chu==0)?10:15;
//分
seg_buf[6]=(chu==0)?10:time_chu[1]/16;
seg_buf[7]=(chu==0)?10:time_chu[1]%16;
seg_point[6]=0;
}
break;
case 2://参数界面
seg_buf[0]=12;//P
seg_buf[1]=10;
seg_buf[2]=10;
seg_buf[3]=10;
seg_buf[4]=10;
seg_buf[5]=10;
seg_buf[6]=wcan_seg/10;
seg_buf[7]=wcan_seg%10;
seg_point[6]=0;
break;
// case 3://棰戠巼鏄剧ず鐣岄潰
// seg_buf[0]=6;
// seg_point[5]=0;
// seg_buf[1]=(freq>=1000000)?freq/1000000:10;
// seg_buf[2]=(freq>=100000)? freq/100000%10:10;
// seg_buf[3]=(freq>=10000)?freq/10000%10:10;
//
// seg_buf[4]=(freq>=1000)?freq/1000%10:10;
// seg_buf[5]=(freq>=100)?freq/100%10:10;
// seg_buf[6]=(freq>=10)?freq/10%10:10;
// seg_buf[7]=(freq>=1)?freq%10:0;
break;
}
}
if(seg_t==1)//显示温湿度界面
{
seg_buf[0]=18;//E
seg_buf[1]=10;
seg_buf[2]=10;
seg_buf[3]=(unsigned char )tem/10;
seg_buf[4]=(unsigned char )tem%10;
seg_buf[5]=15;
seg_buf[6]=(wuxiao==1)?19:(unsigned char )shi/10;
seg_buf[7]=(wuxiao==1)?19:(unsigned char )shi%10;
seg_point[6]=0;
}
}
void Delay750ms(void) //@12.000MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 35;
j = 51;
k = 182;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void led_proc()
{
//界面指示灯
ucled[0]=(segmode==0&&seg_t==0)?1:0;
ucled[1]=(segmode==1&&seg_t==0)?1:0;
ucled[2]=(seg_t==1)?1:0;
//报警指示灯
ucled[3]=(tem>(wcan_seg))?f100ms:0;
ucled[4]=(wuxiao==1)?1:0;
if(chu>=2)
{
if(tem_old<tem&&shi_old<shi)
{
ucled[5]=1;
}
else ucled[5]=0;
}
}
void ad_proc()//亮暗状态变化感知时间
{
if(ad_slow_down<70)return ;
ad_slow_down=0;
if(f3s==0)//过了3s,才能再次触发
{
dangg_old=dangg;//保存上一次的状态
v_zhen=ad_zhuanhuan(0x41)/51.0;
if(v_zhen<2.50)//光敏电阻在“挡光”条件下
{
dangg=1;//光敏电阻在挡光条件下,“暗状态”
}
else
{
dangg=0;//"亮"状态
}
if(dangg_old==0&&dangg==1)
{
cai=1;//触发一次温度、湿度数据采集功能
}
}
}
void main()
{
Delay750ms();
rd_temperature();//延时一下再解决上电85
sys_init();
Timer1_Init();
Timer0_Init();
set_rtc(time);
while(1)
{
led_proc();
key_proc();
seg_proc();
led_proc();
ad_proc();
}
}
seg.c
#include <seg.h>
unsigned char code seg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned char code seg_duan[]={0xC0,0xF9,0xA4,0xB0,0x99,
0x92,0x82,0xF8,0x80,0x90,
0xff,0xc1,0x8c,0xc8,0x8e,0xbf,0xc6,0x89,0x86,0X88};
//11-u锛?2-P锛?3-N锛?4-F,15--,16-C,17-H,18-E,19-A
void seg_disp(unsigned char wei,duan,point)
{
P0=0xff;
P2=P2&0x1f|0xe0;//娈甸€?
P2&=0x1f;
P0=seg_wei[wei];
P2=P2&0x1f|0xc0;//浣嶉€?
P2&=0x1f;
P0=seg_duan[duan];
if(point==1)P0&=0x7f;
P2=P2&0x1f|0xe0;//娈甸€?
P2&=0x1f;
}
key.c
#include <key.h>
unsigned char key_read(void)
{
unsigned char temp=0;
AUXR &=~0X10;//关闭定时器2
P44=0;P42=1;P35=1;
//P34=1;
if(P30==0)temp=7;
if(P31==0)temp=6;
if(P32==0)temp=5;
if(P33==0)temp=4;
P44=1;P42=0;P35=1;
//P34=1;
if(P30==0)temp=11;
if(P31==0)temp=10;
if(P32==0)temp=9;
if(P33==0)temp=8;
P44=1;P42=1;P35=0;
//P34=1;
if(P30==0)temp=15;
if(P31==0)temp=14;
if(P32==0)temp=13;
if(P33==0)temp=12;
P44=1;P42=1;P35=1;
//P34=0;
// if(P30==0)temp=19;
// if(P31==0)temp=18;
// if(P32==0)temp=17;
// if(P33==0)temp=16;
AUXR|=0X10;//开启定时器2
return temp;
}
init.c
#include <init.h>
void sys_init()
{
P0=0xff;//led
P2=(P2&0x1f)|0x80;
P2&=0x1f;
P0=0x00;//蜂鸣器
P2=(P2&0x1f)|0xa0;
P2&=0x1f;
}
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x18; //设置定时初始值
TH1 = 0xFC; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1=1;
EA=1;
}
void Timer0_Init(void) //100微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD|=0X05;
TL0 = 0; //设置定时初始值
TH0 = 0; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
led.c
#include <led.h>
idata unsigned char temp_1 = 0x00;
idata unsigned char temp_old_1 = 0xff;
void Led_Disp(unsigned char *ucLed)
{
unsigned char temp;
temp_1=0x00;
temp_1 = (ucLed[0] << 0) | (ucLed[1] << 1) | (ucLed[2] << 2) | (ucLed[3] << 3) |
(ucLed[4] << 4) | (ucLed[5] << 5) | (ucLed[6] << 6) | (ucLed[7] << 7);
if (temp_1 != temp_old_1)
{
P0 = ~temp_1;
// 操作P2锁存器
temp = P2 & 0x1f; // 保留P2的低5位
temp = temp | 0x80; // 与0x80进行或操作
P2 = temp; // 写入P2
temp = P2 & 0x1f; // 保留P2的低5位
P2 = temp; // 写入P2,关闭锁存器
temp_old_1 = temp_1;
}
}
idata unsigned char temp_0 = 0x00;
idata unsigned char temp_old_0 = 0xff;
/// 蜂鸣器控制
//void Beep(bit enable)
//{
// unsigned char temp;
// EA=0;
// if (enable)
// temp_0 |= 0x40;
// else
// temp_0 &= ~(0x40);
// if (temp_0 != temp_old_0)
// {
// P0 = temp_0;
//
// // 操作P2锁存器
// temp = P2 & 0x1f; // 保留P2的低5位
// temp = temp | 0xa0; // 与0xa0进行或操作
// P2 = temp; // 写入P2
// temp = P2 & 0x1f; // 保留P2的低5位
// P2 = temp; // 写入P2,关闭锁存器
//
// temp_old_0 = temp_0;
// }
// EA=1;
//}
///// 继电器控制
///
//void Relay(bit enable)
//{
// unsigned char temp;
// EA=0;//防止总线冲突
// if (enable)
// temp_0 |= 0x10;
// else
// temp_0 &= ~(0x10);
// if (temp_0 != temp_old_0)
// {
// P0 = temp_0;
//
// // 操作P2锁存器
// temp = P2 & 0x1f; // 保留P2的低5位
// temp = temp | 0xa0; // 与0xa0进行或操作
// P2 = temp; // 写入P2
// temp = P2 & 0x1f; // 保留P2的低5位
// P2 = temp; // 写入P2,关闭锁存器
//
// temp_old_0 = temp_0;
// }
// EA=1;
//}
ds18b20.c
#include <ds18b20.h>
sbit DQ=P1^4;
void Delay_OneWire(unsigned int 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 rd_temperature()
//{
// unsigned char low,high;//低八位,高八位
//
// EA=0; init_ds18b20(); EA=1;//初始化
// EA=0; Write_DS18B20(0xcc); EA=1;//跳过ROM
// EA=0; Write_DS18B20(0x44); EA=1;//温度转换
// Delay_OneWire(200);
// EA=0; init_ds18b20(); EA=1;
// EA=0; Write_DS18B20(0xcc); EA=1;//跳过ROM
// EA=0; Write_DS18B20(0xbe); EA=1;//读取温度,而且这种写法其实读到的是上一次转换的温度
// EA=0; low=Read_DS18B20(); EA=1;
// EA=0; high=Read_DS18B20(); EA=1;
// return (float)(high<<8|low)*0.0625;
// //先将数据变成八位二进制数,然后转换成float型,再乘精度
//}
1+2+2
1+2
float rd_temperature()
{
unsigned char low,high;//低八位,高八位
// 1. 先读取【上一次】已经转换好的温度(完全不需要 Delay)
EA=0; init_ds18b20(); EA=1;
EA=0; Write_DS18B20(0xcc); EA=1;//跳过ROM
EA=0; Write_DS18B20(0xbe); EA=1;//读取温度,
EA=0; low=Read_DS18B20(); EA=1;
EA=0; high=Read_DS18B20(); EA=1;
// 2. 紧接着发送【下一次】温度转换命令(发完直接走人,让它自己慢慢转)
EA=0; init_ds18b20(); EA=1;
EA=0; Write_DS18B20(0xcc); EA=1;//跳过ROM
EA=0; Write_DS18B20(0x44); EA=1;//温度转换
// 3. 计算并返回刚才读到的数据
return ((float)(high<<8|low))*0.0625;
}
//float rd_temperature(void)
//{
// unsigned char high;
// unsigned char low;
// init_ds18b20();
// Write_DS18B20(0xcc);
// Write_DS18B20(0x44);
//
// init_ds18b20();
// Write_DS18B20(0xcc);
// Write_DS18B20(0xbe);
// low=Read_DS18B20();
// high=Read_DS18B20();
// return ((high<<8)|low)/16.0;
//}
ds1302.c
#include <ds1302.h>
#include <intrins.h>
sbit SDA=P2^3;
sbit RST=P1^3;
sbit SCK=P1^7;
unsigned char code write_rtc_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code read_rtc_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
void set_rtc(unsigned char *time)
{
unsigned char i;
EA = 0;//开始通信,关闭中断保护时序和P2口
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
Write_Ds1302_Byte(write_rtc_addr[i],time[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
EA = 1; // 通信结束,立刻恢复中断
}
void read_rtc(unsigned char *time)
{
unsigned char i;
EA = 0; // 开始通信,关闭中断保护时序和P2口
for(i=0;i<7;i++)
{
time[i]=Read_Ds1302_Byte (read_rtc_addr[i]);
}
EA = 1; // 通信结束,立刻恢复中断
}
//完全不需要操心时序会不会被数码管定时器打断的问题
pcf8591.c
#include <pcf8591.h>
/* # I2C浠g爜鐗囨璇存槑
1. 鏈枃浠跺す涓彁渚涚殑椹卞姩浠g爜渚涘弬璧涢€夋墜瀹屾垚绋嬪簭璁捐鍙傝€冦€?
2. 鍙傝禌閫夋墜鍙互鑷缂栧啓鐩稿叧浠g爜鎴栦互璇ヤ唬鐮佷负鍩虹锛屾牴鎹墍閫夊崟鐗囨満绫诲瀷銆佽繍琛岄€熷害鍜岃瘯棰?
涓鍗曠墖鏈烘椂閽熼鐜囩殑瑕佹眰锛岃繘琛屼唬鐮佽皟璇曞拰淇敼銆?
*/
#define DELAY_TIME 1
sbit scl=P2^0;
sbit sda=P2^1;
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
//1+2+2
//1+2+4
unsigned char ad_zhuanhuan(unsigned char addr)
{
unsigned char temp=0;
EA=0;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
temp=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
EA=1;
return temp;
}
//1+2+2+2+1
//void da_zhuanhuan(unsigned char dat)
//{
//EA=0;
// I2CStart();
// I2CSendByte(0x90);
// I2CWaitAck();
//
// I2CSendByte(0x41);
// I2CWaitAck();
//
// I2CSendByte(dat);
// I2CWaitAck();
// I2CStop();
//EA=1;
//}
//1+2+2
//1+2
//while+1
//void ee_read(unsigned char *str,unsigned char addr,unsigned char num)
//{
// EA=0;
//
// I2CStart();
// I2CSendByte(0xa0);
// I2CWaitAck();
//
// I2CSendByte(addr);
// I2CWaitAck();
//
// I2CStart();
// I2CSendByte(0xa1);
// I2CWaitAck();
//
// while(num--)
// {
// *str++=I2CReceiveByte();
// if(num)I2CSendAck(0);
// else I2CSendAck(1);
// }
// I2CStop();
//
// EA=1;
//}
//1+2+2
////while+5
//void ee_write(unsigned char *str,unsigned char addr,unsigned char num)
//{
// EA=0;
// I2CStart();
// I2CSendByte(0xa0);
// I2CWaitAck();
//
// I2CSendByte(addr);
// I2CWaitAck();
//
// while(num--)
// {
// I2CSendByte(*str++);
// I2CWaitAck();
// I2C_Delay(200);
// }
// I2CStop();
//
// EA=1;
// I2C_Delay(255);
// I2C_Delay(255);
// I2C_Delay(255);
// I2C_Delay(255);
//}
更多推荐



所有评论(0)