从上个寒假开始就接触学习stc89c52,到现在也有七八个月了。虽然做过的东西不算多,但感觉总有很多模块是经常要用到的,无论是测试的时候,还是作品成型的时候。但是,在做一个新的作品的时候,除了学习一些新模块,很多都是在重复着之前的工作。郁闷的是,虽然是之前测试通过的模块,调试还是会费很多时间。所以,就有了把各个模块封装整理成最小最简单的函数的想法,以后要用的时候,直接调用就行了。这样就可以不必浪费时间在一些不必要的时间上。
延时篇
不要求特别精确的时候可以用,在根据时序图写程序也可以用。
void delayms(uint xms) //毫秒级的
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}
//晶振为11.0592Mhz
void delayus(uint xus) //微秒级
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
nop();
}
//晶振为11.0592Mhz
显示篇
led:这个是最简单的了,led串个电阻,一端接VCC,另一端接IO口,当给低电平时,灯就亮了。如果说在上机位写程序是从Hollow world开始的话,那么单片机就是从点亮第一个发光二极管开始的。用led,最常用来的就是用来检测其他模块能否正常工作了,比如说,红外遥控,为确保能直观看到这个模块是否正常,用led来检测是最好不过了。
sbit led1=P1^0;
led1=0;
lcd1602:因为一般从其他模块的得到数据,要显示出来,一般习惯用液晶屏来显示。用1602也比较简单,不过缺点是占到的IO口太多了,3个控制线+8个信号线。在51上就占了11/36。不过用来测试还是比较方便的。
sbit rs=P1^0;
sbit rw=P1^1;
sbit E=P2^5; //根据原理图改
void WriteCom(uchar j) //写指令
{
rs=0;
rw=0;
E=0; //使能端需要一个高脉冲
P0=j; //数据码输入端,这时写的是指令
delayms(5);
E=1;
delayms(5);
E=0;
}
void WriteData(uchar a) //写数据
{
rs=1;
rw=0;
P0=a; //写的是字
E=0; //使能端也是高脉冲
delayms(5);
E=1;
delayms(5);
E=0;
}
void InitLCD() //显示模式及光标的等设置
{
WriteCom(0x38);//显示模式设置
WriteCom(0x0c); //显示开/关及光标设置00001DC //D=0、1:关、开显示;C=0、1:关、开光标;B=0、1:不显示、开光标闪烁。
WriteCom(0x01); // 显示清屏
WriteCom(0x06); //
}
void display(uchar rol, uchar num,uchar dat) //行数,列数,数据
{
if(rol == 1)
{
WriteCom(0x80+num);
WriteData(0x30+dat);
}
if(rol == 2)
{
WriteCom(0x80+0x40+num);
WriteData(0x30+dat);
}
}
void dis_dy(uchar rol, float t) //要怎么显示,具体在这里改。主函数中调用这个就行.在这里是显示x.xxxx
{
mm=t/1024*5*10000;
shuzi1=mm/10000;
shuzi2=mm/1000%10;
shuzi3=mm/100%10;
shuzi4=mm/10%10;
shuzi5=mm%10;
display(rol, 4,shuzi1);
WriteData('.');
display(rol, 6,shuzi2);
display(rol, 7,shuzi3);
display(rol, 8,shuzi4);
display(rol, 9,shuzi5);
}
数码管:
传感器篇
就现在接触传感器来,感觉传感器分为三种,一是:传感器芯片连电位器,再连接到一个电压比较器,通过比较输出,高低电平。比如,智能小车检测黑线循迹用的TCRT5000,检测人体有无的红外热释探头;二是“含有处理器”的传感器,他们可以看做是和在单片机进行通信,在单片机给他进行操作后,传感器将检测到的数值一位一位的传给单片机,然后单片机再一位位的处理,得到要检测的值。比如单总线连接的dht11,ds18b20等;三是,不同数值就有不同的电压输出,这种传感器要经过AD转化,和公式转化,才能得具体数值,比如检测CO的MQ-5。检测角度的角度传感器等等。
其中第一种是电平输出的基本就不需要代码的,第二种,看时序图,移位是关键,但一般常见的传感器,网上或商家的资料是很多的,主要是要看懂。因为可能例程是添加了很多其他你不用用到的东东。或者在一些时间延时上,不同处理器的时间也是不同,从51移植到其他单片机,就需要改动了。第三种主要就是在AD转化上。
ds18b20温度检测部分代码:
18B20程序// stc12系列的
void ds18b20_Reset(void) //18B20复位,初始化函数
{
unsigned char x = 0;
DQ = 1;
delayxus(60);
DQ = 0;
delayxus(240);
delayxus(240);
DQ = 1;
delayxus(80);
x = DQ;
delayxus(120);
}
uchar ds18b20_ReadByte(void)
{
unsigned char i = 0;
unsigned char dat = 0;
for(i = 0;i < 8;i ++)
{
DQ = 0;
dat >>= 1;
delayxus(1);
DQ = 1;
delayxus(1);
if(DQ)
dat |= 0x80;
delayxus(60);
}
return (dat);
}
void ds18b20_WriteByte(unsigned char dat) //向18B20写一个字节数据
{
unsigned char i = 0;
for(i = 0;i < 8;i ++)
{
DQ = 0;
DQ = dat&0x01;
delayxus(1);
delayxus(60);
DQ = 1;
dat >>= 1;
delayxus(1);
}
}
ReadTemperature(void) //读取寄存器中存储的温度数据 数据类型是整形,为当前温度的10倍。
{
unsigned int a = 0;
unsigned int b = 0;
unsigned int temp = 0;
float tt = 0;
ds18b20_Reset();
ds18b20_WriteByte(0xCC);
ds18b20_WriteByte(0x44);
ds18b20_Reset();
ds18b20_WriteByte(0xCC);
ds18b20_WriteByte(0xBE);
a = ds18b20_ReadByte();
b = ds18b20_ReadByte();
temp=b;
temp<<=8; //两个字节组合为1个字
temp=temp|a;
f_temp=temp*0.0625; //温度在寄存器中为12位 分辨率位0.0625°
temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入
f_temp=f_temp+0.05;
return temp; //temp是整型
}
AD检测例程加显示//stc12内部自带AD
通讯篇
两个但单片机通过RXD,TXD通讯;
红外遥控;