51单片机应用从零开始:https://www.elecfans.com/soft/33/2012/20121023293924.html
2014-11-11 11:18
本帖最后由 eehome 于 2013-1-5 09:45 编辑 51单片机应用从零开始
2012-08-17 14:53
维的测量——定时,计数器第10章与外界的沟通——串行口通信第11章程序设计的魅力——中断控制《51单片机应用从零开始》PDF电子版附件:[hide][/hide]`
2017-11-19 14:12
附加下载地址http://520fuli.ctfile.com/fs/eUv146506901
2016-03-23 19:52
前面电子设计从零开始这本书看的云里雾里,
2021-07-21 07:45
【从零开始学习单片机系列】第01章单片机基础
2016-01-06 17:57
本帖最后由 eehome 于 2013-1-5 10:07 编辑 LCD数字时钟,这次使用了DS1302时钟芯片,断电后仍能继续保持准确的时间。代码:main.c#include<reg51.h>#include"ds1302.c"#include"lcd1602.c"#define uint unsigned int#define uchar unsigned char***it k1 = P3^0;***it k2 = P3^1;***it k3 = P3^2;***it k4 = P3^3;uchar count,miao,fen,shi,k1num;uchar xiqi,ri,yue,nian;uchar _time_[7];uchar code table[] = " 20-- ";uchar code table_week[8][4] = {"Sun ","Mon ","Tus ","Wed ","Thr ","Fri ","Sat ","Sun "};void LCD1602_wrt_sfm ( uchar add , uchar dt ) { uchar sh,ge; sh = dt/10; ge= dt%10; LCD1602_wrt_cmd(0x80+0x40+add); LCD1602_wrt_dt(0x30+sh); LCD1602_wrt_dt(0x30+ge);}void LCD1602_wrt_date ( uchar add , uchar dt ) { uchar sh,ge; sh = dt/10; ge= dt%10; LCD1602_wrt_cmd(0x80+add); LCD1602_wrt_dt(0x30+sh); LCD1602_wrt_dt(0x30+ge);} void LCD1602_wrt_week ( uchar dt ) { LCD1602_wrt_cmd(0x80+12); LCD1602_wrt_dt(table_week[dt][0]); LCD1602_wrt_dt(table_week[dt][1]); LCD1602_wrt_dt(table_week[dt][2]);}void init() { uchar num; LCD1602_EN = 0; Read_RTC( _time_ ); miao = _time_[0]; fen = _time_[1]; shi = _time_[2]; ri = _time_[3]; yue = _time_[4]; nian = _time_[6]; xiqi = _time_[5]; LCD1602_wrt_cmd(0x38); delay(5); LCD1602_wrt_cmd(0x38); delay(5); LCD1602_wrt_cmd(0x38); delay(5); LCD1602_wrt_cmd(0x0c); delay(5); LCD1602_wrt_cmd(0x06); delay(5); LCD1602_wrt_cmd(0x01); delay(5); LCD1602_wrt_cmd(0x80); delay(5); for( num=0 ; num<15 ; num++ ) {LCD1602_wrt_dt( table[num] );delay(5); } LCD1602_wrt_cmd(0x80+0x40+6); LCD1602_wrt_dt(':'); delay(5); LCD1602_wrt_cmd(0x80+0x40+9); LCD1602_wrt_dt(':'); delay(5); LCD1602_wrt_date(3,nian); LCD1602_wrt_date(6,yue); LCD1602_wrt_date(9,ri); LCD1602_wrt_week(xiqi); LCD1602_wrt_sfm(10,miao); LCD1602_wrt_sfm(7,fen); LCD1602_wrt_sfm(4,shi); TMOD = 0x01; TH0 = (65536-49998)/256; TL0 = (65536-49998)%256; EA = 1; ET0 = 1; TR0 = 1;}void keyscan () { if ( !k1 ) {delay(10);if ( !k1 ) {k1num++;while ( !k1 ) Bp( 20 );if ( 1==k1num ) { TR0 = 0; LCD1602_wrt_cmd(0x80+0x40+11); LCD1602_wrt_cmd(0x0f);}if ( 2==k1num ) {LCD1602_wrt_cmd(0x80+0x40+8);}if ( 3==k1num ) { LCD1602_wrt_cmd(0x80+0x40+5);}if ( 4==k1num ) {LCD1602_wrt_cmd(0x80+14);}if ( 5==k1num ) { LCD1602_wrt_cmd(0x80+10);}if ( 6==k1num ) {LCD1602_wrt_cmd(0x80+7);}if ( 7==k1num ) { LCD1602_wrt_cmd(0x80+4);}if ( 8==k1num ) { k1num = 1; LCD1602_wrt_cmd(0x80+0x40+11);}} } if ( k1num ) {if ( !k2 ) { delay(10);if ( !k2 ) {while ( !k2 ) Bp( 20 ); if ( 1==k1num ) { miao++;if ( 60==miao ) miao=0;LCD1602_wrt_sfm(10,miao);//Write_RTC_adr(0,miao);LCD1602_wrt_cmd(0x80+0x40+11); } if ( 2==k1num ) {fen++;if ( 60==fen ) fen=0;LCD1602_wrt_sfm(7,fen);//Write_RTC_adr(1,fen);LCD1602_wrt_cmd(0x80+0x40+8); } if ( 3==k1num ) {shi++;if ( 24==shi ) shi=0;LCD1602_wrt_sfm(4,shi);//Write_RTC_adr(2,shi);LCD1602_wrt_cmd(0x80+0x40+5); } if ( 4==k1num ) {xiqi++;if ( 7==xiqi ) xiqi = 0;LCD1602_wrt_week(xiqi);Write_RTC_adr(5,xiqi);LCD1602_wrt_cmd(0x80+14); } if ( 5==k1num ) {ri++;if ( 32==ri ) ri = 1;LCD1602_wrt_date(9,ri);Write_RTC_adr(3,ri);LCD1602_wrt_cmd(0x80+10); } if ( 6==k1num ) {yue++;if ( 13==yue ) yue = 1;LCD1602_wrt_date(6,yue);//Write_RTC_adr(4,yue);LCD1602_wrt_cmd(0x80+7); } if ( 7==k1num ) {nian++;if ( 100==nian ) nian = 0;LCD1602_wrt_date(3,nian);//Write_RTC_adr(6,nian);LCD1602_wrt_cmd(0x80+4); }}} } if ( k1num ) {if ( !k3 ) { delay(10);if ( !k3 ) {while ( !k3 ) Bp( 20 ); if ( 1==k1num ) { miao--;if ( -1==miao ) miao=59;LCD1602_wrt_sfm(10,miao);//Write_RTC_adr(0,miao);LCD1602_wrt_cmd(0x80+0x40+11); } if ( 2==k1num ) {fen--;if ( -1==fen ) fen=59;LCD1602_wrt_sfm(7,fen);//Write_RTC_adr(1,fen);LCD1602_wrt_cmd(0x80+0x40+8); } if ( 3==k1num ) {shi--;if ( -1==shi ) shi=23;LCD1602_wrt_sfm(4,shi);//Write_RTC_adr(2,shi);LCD1602_wrt_cmd(0x80+0x40+5); } if ( 4==k1num ) {xiqi--;if ( -1==xiqi ) xiqi = 6;LCD1602_wrt_week(xiqi);Write_RTC_adr(5,xiqi);LCD1602_wrt_cmd(0x80+14); } if ( 5==k1num ) {ri--;if ( 0==ri ) ri = 31;LCD1602_wrt_date(9,ri);//Write_RTC_adr(3,ri);LCD1602_wrt_cmd(0x80+10); } if ( 6==k1num ) {yue--;if ( 0==yue ) yue = 12;LCD1602_wrt_date(6,yue);//Write_RTC_adr(4,yue);LCD1602_wrt_cmd(0x80+7); } if ( 7==k1num ) {nian--;if ( -1==nian ) nian = 99;LCD1602_wrt_date(3,nian);//Write_RTC_adr(6,nian);LCD1602_wrt_cmd(0x80+4); }}} } if ( k1num ) {if ( !k4 ) { delay(10);if ( !k4 ) {while ( !k4 ) Bp( 20 ); k1num = 0; LCD1602_wrt_cmd(0x0c); Write_RTC_adr(0,miao); Write_RTC_adr(1,fen); Write_RTC_adr(2,shi); Write_RTC_adr(3,ri); Write_RTC_adr(4,yue); Write_RTC_adr(5,xiqi); Write_RTC_adr(6,nian); TR0 = 1;}} }}void main () {init(); while(1) {keyscan(); }}void time0 () interrupt 1 {TH0 = (65536-49998)/256; TL0 = (65536-49998)%256; count++; if ( 5==count ){ count=0;Read_RTC( _time_ );miao = _time_[0];fen = _time_[1];shi = _time_[2];ri = _time_[3];yue = _time_[4];nian = _time_[6];xiqi = _time_[5];LCD1602_wrt_sfm(10,miao);if ( 0==miao ) LCD1602_wrt_sfm(7,fen);if ( 0==fen ) LCD1602_wrt_sfm(4,shi);if ( 0==shi ) LCD1602_wrt_date(9,ri);if ( 1==ri ) LCD1602_wrt_date(6,yue);if ( 0==shi ) LCD1602_wrt_week(xiqi);if ( 1==yue ) LCD1602_wrt_date(3,nian); }}DS1302.c***it SCK=P3^6; //时钟 ***it SDA=P3^4; //数据 ***it RST=P3^5;// DS1302复位unsigned char code write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分时日月周年 最低位读写位unsigned char code read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};void _delay_() { ;;}/******************************************************************//* 写一个字节*//******************************************************************/void Write_Ds1302_Byte(unsignedchar temp) { unsigned char i; for (i=0;i<8;i++)//循环8次 写入数据{ SCK=0;SDA=temp&0x01;//每次传输低字节 temp>>=1; //右移一位SCK=1;}}/******************************************************************//*写入DS1302*//******************************************************************/void Write_Ds1302( unsigned char address,unsigned char dat ){RST=0; _delay_();SCK=0; _delay_();RST=1; _delay_();//启动Write_Ds1302_Byte(address); //发送地址Write_Ds1302_Byte(dat);//发送数据RST=0; //恢复}/******************************************************************//* 读出DS1302数据 *//******************************************************************/unsigned char Read_Ds1302 ( unsigned char address ){unsigned char i,temp=0x00;RST=0; _delay_(); _delay_();SCK=0; _delay_(); _delay_();RST=1; _delay_(); _delay_();Write_Ds1302_Byte(address);for (i=0;i<8;i++)//循环8次 读取数据{if(SDA)temp|=0x80;//每次传输低字节SCK=0;temp>>=1;//右移一位_delay_();_delay_();_delay_();SCK=1; } RST=0; _delay_();//以下为DS1302复位的稳定时间_delay_(); RST=0; SCK=0; _delay_(); _delay_(); _delay_(); _delay_(); SCK=1; _delay_(); _delay_(); SDA=0; _delay_(); _delay_(); SDA=1; _delay_(); _delay_(); return (temp);//返回}/******************************************************************//* 读时钟数据*//******************************************************************/void Read_RTC( unsigned char *q )//读取 日历{unsigned char i,*p,tmp;p=read_rtc_address;//地址传递for(i=0;i<7;i++)//分7次读取 秒分时日月周年{*q=Read_Ds1302(*p); tmp=*q/16; *q%=16; *q+=tmp*10;p++;q++;}}/******************************************************************//*设定时钟数据 *//******************************************************************/void Set_RTC( unsigned char * q){ unsigned char i,*p,tmp; p=write_rtc_address; //传地址 Write_Ds1302(0x8E,0X00); for(i=0;i<7;i++){ tmp=*q/10;*q%=10;*q+=tmp*16;//BCD处理Write_Ds1302(*p,*q);p++;q++; }Write_Ds1302(0x8E,0x80);}unsigned char Read_RTC_adr ( unsigned char address ) { unsigned char k, tmp; k = Read_Ds1302 ( read_rtc_address[address] ); tmp=k/16; k%=16; k+=tmp*10; return k;} //读指定位置void Write_RTC_adr ( unsigned char address , unsigned char k ) {unsigned char tmp; tmp=k/10; k%=10; k+=tmp*16; Write_Ds1302(0x8E,0X00); Write_Ds1302( write_rtc_address[address] , k ); Write_Ds1302(0x8E,0X80);}LCD1602.c***it LCD1602_RS = P2^6;***it LCD1602_RW = P2^5;***it LCD1602_EN = P2^7;***it Beep = P1^5;void delay ( unsigned int z ) {//粗略延时 unsigned int x,y; for ( x=z ; x>0 ; x-- )for ( y=110 ; y>0 ; y-- );}void Bp ( unsigned int z ) {//蜂鸣器 unsigned int x; for ( x=z ; x>0 ; x-- ) {Beep = 0;delay(1);Beep = 1;delay(1); }}void LCD1602_wrt_cmd ( unsigned char cmd ) {//液晶写命令 LCD1602 LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_EN = 0; P0 = cmd; delay(5); LCD1602_EN = 1; delay(5); LCD1602_EN = 0;}void LCD1602_wrt_dt ( unsigned char dt ) {//液晶写数据 LCD1602 LCD1602_RS = 1; LCD1602_RW = 0; LCD1602_EN = 0; P0 = dt; delay(5); LCD1602_EN = 1; delay(5); LCD1602_EN = 0;}
2012-12-11 22:28
本帖最后由 eehome 于 2013-1-5 10:08 编辑 独立键盘控制LED灯:(效果:摁一下亮,再摁一下灭,8个开关8个灯,相互独立)代码:#include <reg51.h>void delay(unsigned int i);main(){ unsigned char P0temp; while (1) {if ( ~P0 ) {P0temp = P0;while( P0==P0temp );//自己想出来的消抖方法P2 ^= ~P0temp; delay( 100 );} }}void delay(unsigned int i){ unsigned char j; for(i; i > 0; i--) for(j = 255; j > 0; j--);}心得:调试的时候发现按键抖动的问题,当时不知道这个关键词,苦思很久才想出来这么一个,虽然不太官方,但当时还是挺有成就感的。(忆)
2012-12-11 22:04
本帖最后由 eehome 于 2013-1-5 10:08 编辑 动态数码管: (采用138译码器进行位选)代码://==========================================#include<reg51.h>#define uchar unsigned char#define uint unsigned int//------------------------------------------uchar shi_temp;uchar shi_cf;uchar shi_cf_shi;uchar shi_cf_ge;uchar code table[]={ 0x3f , 0x06 , 0x5b , 0x4f , 0x66 , 0x6d , 0x7d , 0x07 , 0x7f , 0x6f , 0x77 , 0x7c , 0x39 , 0x5e , 0x79 , 0x71 };uchar code table2[]={ 0xbf , 0x86 , 0xdb , 0xcf , 0xe6 , 0xed , 0xfd , 0x87 , 0xff , 0xef , 0x77 , 0x7c , 0x39 , 0x5e , 0x79 , 0x71 };// 更好的方法是:table[N]|0x80 void delayms( uint );void display( uchar , uchar );uchar num , num1 , num2 , shi , ge;//===========================================void main () { TMOD = 0x11; TH0 = (65536-50000)/256; TL0 = (65536-50000)%256; TH0 = (65536-50000)/256; TL0 = (65536-50000)%256; EA = 1; ET1 = 1;//TR0 = 1; TR1 = 1; while (1) {display( shi , ge ); }}//============================================void display( uchar shi , uchar ge ) { if ( shi < shi_temp ) {shi_cf++;if ( 24 == shi_cf ) {shi_cf = 0 ;}shi_cf_ge = shi_cf%10;shi_cf_shi = shi_cf/10; } shi_temp = shi; P2 = 0xf3; P0 = 0x00; P0 = table[shi_cf_shi]; delayms( 2 ); P2 = 0xf7; P0 = 0x00; P0 = table2[shi_cf_ge]; delayms( 2 ); P2 = 0xfb; P0 = 0x00; P0 = table[shi]; delayms( 2 ); P2 = 0xff; P0 = 0x00; P0 = table[ge]; delayms( 2 );}//----------------------------------------void delayms( uint xms ) { uint i , j; for ( i = xms ; i>0 ; i-- ) {for ( j = 110 ; j>0 ; j-- ); }}//=========================================void T1_time () interrupt 3 {TH1 = (65536-50000)/256;TL1 = (65536-50000)%256;num2++;if ( 2 == num2 ) {num2 = 0;num++;if ( 60 == num ) {num = 0;}shi = num/10;ge = num%10;}}//===========================================心得:学会了动态数码管的扫描显示方法,同时初步接触了定时器中断。(忆)
2012-12-11 22:11
本帖最后由 eehome 于 2013-1-5 10:08 编辑 蜂鸣器歌曲初试,《祝你生日快乐》。代码:#include<reg51.h>***it Beep = P1^5;unsigned char n=0;unsigned char code music_tab0[]={0,204,182,162,153,136,121,114,102,91,81,76};unsigned char code music_tab1[]={1,1,2,1,4,3,1,1,2,1,5,4,1,1,8,6,4,3,9,7,7,6,4,5,4,0};unsigned char code music_tab2[]={2,2,4,4,4,8,2,2,4,4,4,8,2,2,4,4,4,4,4,2,2,4,4,4,8,0};void delay ( unsigned char m ) { unsigned char i; for ( i=m ; i>0 ; i-- );} void main() { unsigned char m; unsigned char i=0; TMOD=0x01; TH0=0xd8; TL0=0xef; EA=1; ET0=1; TR0=1; i=0; while(1){m = music_tab0[music_tab1];n = 15 * music_tab2;if ( 0==m ) break;i++;while(n!=0) {Beep = ~Beep;delay (m);}delay (60000); } for ( i=0 ; i<201 ; i++ ) {delay (60000); }}void timer0() interrupt 1 { TH0=0xd8; TL0=0xef; n--;}心得:以前觉得用蜂鸣器放歌是非常难的,但是经过尝试以后才发现,有些东西并没有想象的那么难,如果你愿意去尝试的话。这个程序的“204,182,162,153,136,121,114,102,91,81,76”是自己用Excel一个个计算出来的,主要是其中比例的关系。其他具体参数是自己边调试边调整的。
2012-12-11 22:34