51单片机应用
从上个寒假开始就接触学习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通讯;
红外遥控;