数字管和按钮绝对是必不可少的模块。
数字管,主要是消隐和小数点。
#include "sys.h" uchar code nixie[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff}; void DisplayBit(uchar pos,value,bit k) { P0 = 0X00; Select_74HC138(6); Select_74HC138(0); if(k) //显示小数点 P0 = nixie[value] & 0x7f; else //不显示小数点 P0 = nixie[value]; Select_74HC138(7); Select_74HC138(0); P0 = _crol_(0x01,pos); Select_74HC138(6); Select_74HC138(0); Delay(1); }
有时候,任何数字管都要显示(其实这并不常用)
//显示任意长度的数字 uchar w[8]; void DisplaySMG(unsigned long num) { uchar pos,len; unsigned long temp = 1; for(len = 0; len < 8; len ) { w[len] = num / temp % 10; temp *= 10; if(num < temp) break; } len ; for(pos = 0; pos < len; pos ) DisplayBit(pos,w[len-1-pos],0); }
二是按键
独立按钮很容易写
sbit s4 = P3^3; sbit s5 = P3^2; sbit s6 = P3^1; sbit s7 = P3^0; uchar key_val = 20; void KeyScans() { if(s4 == 0) { Delay(10); key_val = 4; while(s4 == 0) { } } if(s5 == 0) { Delay(10); key_val = 5; while(s5 == 0) { } } if(s6 == 0) { Delay(10); key_val = 6; while(s6 == 0) { } } if(s7 == 0) { Delay(10); key_val = 7; while(s7 == 0) { } } }
矩阵按键
sbit h1 = P3^2; sbit h2 = P3^3; sbit l1 = P4^4; sbit l2 = P4^2; void KeyScans() { h1 = 0; l1 = l2 = h2 = 1; if(l1 == 0) { Delay(10); key_val = 5; while(l1 == 0) { } } if(l2 == 0) { Delay(10); key_val = 9; while(l2 == 0) { } } h2 = 0; h1 = l1 = l2 = 1; if(l1 == 0) { Delay(10); key_val = 4; while(l1 == 0) { } } if(l2 == 0) { Delay(10); key_val = 8; while(l2 == 0) { } } }
如果使用所有矩阵按钮,使用上述方法看起来有点头晕
sbit l1 = P4^4; sbit l2 = P4^2; sbit l3 = P3^5; sbit l4 = P3^4; void KeyScans() { uchar hang; for(hang = 0; hang < 4; hang ) { P3 = _cror_(0xf7,hang) & 0xff; if(l1 == 0) { Delay(10); key_val = hang 4*1; while(l1 == 0) { } } if(l2 == 0) { Delay(10); key_val = hang 4*2; while(l2 == 0) { } } if(l3 == 0) { Delay(10); key_val = hang 4*3; while(l3 == 0) { } } if(l4 == 0) { Delay(10); key_val = hang 4*4; while(l4 == 0) { } } } }
在我看来,最头疼的是流水灯,因为如果控制不好,会和数字管发生冲突
void OperateLed(uchar who,status) { static uchar temp; uchar zt; switch(status) { case 0: temp = temp | _crol_(0x01,who-1); P0 = ~temp; break; case 1: if(who == 0xff) { P0 = 0xff; temp = 0; } else { zt = (~temp) | _crol_(0x01,who-1); if(temp != (~zt)) temp = ~zt; P0 = zt; } break; case 2: P0 = ~who; temp = who; break; default: break; } Select_74HC138(4); Select_74HC138(0); }
下面的写法,给0x10是让继电器吸合,但如果你想让蜂鸣器响,给0x50.这不是关闭继电器,所以可以先定义变量stat = 0x00;stat = 0x10; 再stat |= 0x50,就不会了
void Operatews(uchar num,status) { static uchar t; if(status) { t = num; P0 = t; } else { t = t & (~num); P0 = t; } Select_74HC138(5); Select_74HC138(0); }
然后复习NE555频率测量模块,记得连接跳线帽P34和SIGNAL上,不过有一次做题,忘了把跳线帽摘下来,就影响了我的矩阵按键了,因为矩阵按键第4列也接在P当时我以为是板子又坏了。
uint count_freq; uchar t1 = 0; //定时器0用作计数 void Timer0Init() { AUXR |= 0X80; //定时器时钟12T模式 TMOD &= 0XF0; TMOD |= 0X04; //设置计数模式 TL0 = 0XFF; TH0 = 0XFF; TF0 = 0; //TF0 = 1;表示溢出 TR0 = 1; ET0 = 1; EA = 1; } ///定时器1作定时器 void Timer1Init() { AUXR &= 0XBF; TMOD &= 0X0F; TL1 = 0XB0; TH1 = 0X3C; TF1 = 0; TR1 = 1; ET1 = 1; EA = 1; } void ServiceTimer0() interrupt 1 { count_freq ; } void ServiceTimer1() interrupt 3 { t1 ; if(t1 == 20) { t1 = 0; freq = count_freq; count_freq = 0; } }
iic 这应该是我最头疼的问题,但如果你想参加比赛,你只能写数据,然后阅读数据。应该没有模式。除非我上次看到一套真正的问题智能门锁,否则我真的不想写。比赛结束后,我会看那套问题。
IIC读和写
void Write_AT24C02(uchar addr,dat) { IIC_Start(); IIC_SendByte(0xa0); IIC_WaitAck(); IIC_SendByte(addr); IIC_WaitAck(); IIC_SendByte(dat); IIC_WaitAck(); IIC_Stop(); } uchar Read_AT24C02(uchar addr) { uchar dat; IIC_Start(); IIC_SendByte(0xa0); IIC_WaitAck(); IIC_SendByte(addr); IIC_WaitAck(); IIC_Start(); IIC_SendByte(0xa1); IIC_WaitAck(); dat = IIC_RecByte(); IIC_SendAck(1); IIC_Stop(); return dat; }
如果你想读几个数据,写一个,然后适当延迟
Write_AT24C02(0x00,dat[0]); Delay(10); Write_AT24C02(0x01,dat[1]);
最近最近一个看了我们组一个学长一次写几个数字的代码,感觉就像...可以借鉴
void Write_N_AT24C02(uchar *buf,uchar addr,uchar len) { while(len--) { do{ IIC_Start(); IIC_SendBye(0xa0);
if(!IIC_WaitAck())
break;
IIC_Stop();
}while(1);
IIC_SendByte(addr++);
IIC_WaitAck();
IIC_SendByte(*buf++);
IIC_WaitAck();
IIC_Stop();
}
}
然后就是PCF8591了,读数据和写数据都和AT24C02差不多,改下地址就好了
我一般都不怎么喜欢写带返回值的
uchar rb2;
void ReadAIN3()
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
rb2 = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
}
DS1302刚开始学的时候感觉它挺难的,当时一直追着老师问,但是总结了,就也不怎么难了
首先是BCD和十进制的相互转换,可能还有更简洁的方法写,但是,我已经习惯这样写了。。
uchar DAT_chg_BCD(uchar dat)
{
uchar dat1,dat2;
dat1 = dat / 10;
dat2 = dat % 10;
dat2 = dat1*16 + dat2;
return dat2;
}
uchar BCD_chg_DAT(uchar dat)
{
uchar dat1,dat2;
dat1 = dat / 16;
dat2 = dat % 16;
dat2 = dat1*10 + dat2;
return dat2;
}
一开始肯定要往里面写一个时间进去了
void Set_DS1302()
{
uchar i;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0; i < 7; i++)
Write_Ds1302_Byte(WriteReg[i],Time[i]);
Write_Ds1302_Byte(0x8e,0x80);
}
然后把时间读出来
void Get_DS1302()
{
uchar i;
for(i = 0; i < 7; i++)
Time[i] = Read_Ds1302_Byte(ReadReg[i]);
}
当然还要定义一下时间和读写寄存器了
uchar WriteReg[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
uchar ReadReg[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
uchar Time[7] = {55,59,23,0,0,0,0};
然后这个模块就没其他的了。。。
unsigned int temp;
void Temper_Get()
{
unsigned char lsb,msb;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
lsb = Read_DS18B20();
msb = Read_DS18B20();
temp = (msb << 8) | lsb;
if((temp & 0xf8000) == 0x0000)
temp = temp >> 4;
}
一位小数
temp = (msb << 8) | lsb;
temp = temp * 0.625 + 0.5;
两位小数
temp = (msb << 8) | lsb;
temp >>= 4;
temp *= 100;
temp = temp + (lsb&0x0f) * 6.25;
if((msb >> 4) == 0x0f)
temp |= 0x8000;
嗯~再就是超声波了
说实话,一接触超声波还是挺害怕的,但是后来发现它和温度传感器也没有啥区别。如果真的不会用它的话,就当成温度传感器用就好了。
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void Send_Sonic()
{
uchar i = 8;
while(i--)
{
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
uint distance;
void Mea_Distance()
{
uint time = 0;
Send_Sonic();
AUXR &= 0XBF;
TMOD &= 0X0F;
TL1 = 0;
TH1 = 0;
TF1 = 0;
TR1 = 1;
while((RX == 1) && (TF1 == 0));//等待超声波信号返回(RX引脚变为低电平)或等超出测量范围
TR1 = 0;
if(TF1 == 0) //正常范围内
{
time = (TH1 << 8) | TL1;
distance = time * 0.0172;
}
else
{
TF1 = 0;
distance = 999;
}
}
uchar t0 = 0;
void Timer0Init()
{
AUXR &= 0X7F;
TMOD &= 0XF0;
TL0 = 0XB0;
TH0 = 0X3C;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
void ServiceTimer0() interrupt 1
{
t0++;
if(t0 == 20)
{
t0 = 0;
FLAG_WAVE = 1;
}
}
当然也可以减小测量的时间,这里是1s测量一次。。
差不多就这些吧。。