《单片机C语言程序设计实训 100 例—基于 C51+Proteus仿真》案例
第 01 篇 基础程序设计
1 闪烁的 LED
![8650eb44452937b7bf7082cb3e7a01b1.png](https://i-blog.csdnimg.cn/blog_migrate/832b9c9895acafa3e5ce921176a97d0f.jpeg)
/*名称:闪烁的 LED说明:LED 按设定的时间间隔闪烁*/#include#define uchar unsigned char #define uint unsigned int sbit LED=P1^0; //延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){while(1){LED=~LED;DelayMS(150);}}
![5c165d1392382d0e65205a5069f3d086.png](https://i-blog.csdnimg.cn/blog_migrate/f6b6a5d22a13b9adba5bbedf20f05541.jpeg)
2 从左到右的流水灯
/*名称:从左到右的流水灯
说明:接在P0 口的8 个LED从左到右循环依次点亮,产生走马灯效果
*/
#include #include #define uchar unsigned char #define uint unsigned int1//延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){P0=0xfe;while(1){P0=_crol_(P0,1); //P0 的值向左循环移动DelayMS(150);}}
3 8 只 LED 左右来回点亮
/*名称:8 只 LED 左右来回点亮说明:程序利用循环移位函数_crol_和_cror_形成来回滚动的效果*/
![122321b6e47515fbb9860a8b045e5a2f.png](https://i-blog.csdnimg.cn/blog_migrate/eaa30b69603d89299d61949a9fa984cd.jpeg)
#include #include #define uchar unsigned char #define uint unsigned int //延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){uchar i;P2=0x01;while(1){for(i=0;i<7;i++){P2=_crol_(P2,1); //P2 的值向左循环移动DelayMS(150);}for(i=0;i<7;i++){P2=_cror_(P2,1); //P2 的值向右循环移动DelayMS(150);}}}
4 花样流水灯
![eefc0769056ccd9a9a9e482503c7e820.png](https://i-blog.csdnimg.cn/blog_migrate/a8a9838256725b53c6358a8549643e90.jpeg)
/*名称:花样流水灯说明:16 只 LED 分两组按预设的多种花样变换显示*/#include#define uchar unsigned char #define uint unsigned int uchar code Pattern_P0[]= {0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xdb,0xbd,0x7e,0xbd,0xdb,0xe7,0xff,0xe7,0xc3,0x81,0x00,0x81,0xc3,0xe7,0xff,0xaa,0x55,0x18,0xff,0xf0,0x0f,0x00,0xff,0xf8,0xf1,0xe3,0xc7,0x8f,0x1f,0x3f,0x7f,0x7f,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0x00,0x00,0xff,0xff,0x0f,0xf0,0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff};uchar code Pattern_P2[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0xff, 0xe7,0xdb,0xbd,0x7e,0xbd,0xdb,0xe7,0xff,0xe7,0xc3,0x81,0x00,0x81,0xc3,0xe7,0xff, 0xaa,0x55,0x18,0xff,0xf0,0x0f,0x00,0xff,0xf8,0xf1,0xe3,0xc7,0x8f,0x1f,0x3f,0x7f, 0x7f,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0x00,0x00,0xff,0xff,0x0f,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f, 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00, 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff};//延时void DelayMS(uint x){uchar i;while(x--){for(i=0;i<120;i++);}}//主程序void main(){uchar i;while(1){ //从数组中读取数据送至 P0 和 P2 口显示for(i=0;i<136;i++){P0=Pattern_P0[i];P2=Pattern_P2[i];DelayMS(100);}}
![553f9e096236864d68ff3221d8899c82.png](https://i-blog.csdnimg.cn/blog_migrate/a8cbdffff13b0ce51f1d78620ab95cd5.jpeg)
5 LED 模拟交通灯
/*名称:LED 模拟交通灯说明:东西向绿灯亮若干秒,黄灯闪烁 5 次后红灯亮, 红灯亮后,南北向由红灯变为绿灯,若干秒后南北向黄灯闪烁 5 此后变红灯,东西向变绿灯,如此重复。*/#include#define uchar unsigned char#define uint unsigned intsbit YELLOW_B=P0^4;sbit GREEN_B=P0^5;uchar Flash_Count=0,Operation_Type=1; //闪烁次数,操作类型变量//延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++);}//交通灯切换void Traffic_Light(){switch(Operation_Type){case 1://东西向绿灯与南北向红灯亮RED_A=1;YELLOW_A=1;GREEN_A=0;RED_B=0;YELLOW_B=1;GREEN_B=1;DelayMS(2000);Operation_Type=2;break;case 2://东西向黄灯闪烁,绿灯关闭DelayMS(300);YELLOW_A=~YELLOW_A;GREEN_A=1;if(++Flash_Count!=10) return; //闪烁 5 次Flash_Count=0;Operation_Type=3;break;case 3://东西向红灯,南北向绿灯亮RED_A=0;YELLOW_A=1;GREEN_A=1;RED_B=1;YELLOW_B=1;GREEN_B=0;DelayMS(2000);Operation_Type=4;break;case 4://南北向黄灯闪烁 5 次DelayMS(300);YELLOW_B=~YELLOW_B;GREEN_B=1;if(++Flash_Count!=10) return;Flash_Count=0;Operation_Type=1;}}//主程序void main(){while(1) Traffic_Light();}6 单只数码管循环显示 0~9/*名称:单只数码管循环显示 0~9说明:主程序中的循环语句反复将 0~9 的段码送至 P0 口,使数字 0~9 循环显示*/#include#include#define uchar unsigned char#define uint unsigned intuchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //延时
![d6ded67567dac0e419287e5677f09a17.png](https://i-blog.csdnimg.cn/blog_migrate/1a17659a0d4f95cb59ff8d91df9698d2.jpeg)
void DelayMS(uint x){uchar t;while(x--) for(t=0;t<120;t++);}//主程序void main(){uchar i=0;P0=0x00;while(1){P0=~DSY_CODE[i]; i=(i+1)%10; DelayMS(300);
![ca9734c8ada2e7d0da9137e7cec7b7d6.png](https://i-blog.csdnimg.cn/blog_migrate/1f9432c24d9b908504337a09192d512e.jpeg)
}
}
7 . 8 只数码管滚动显示单个数字
/*名称:8 只数码管滚动显示单个数字说明:数码管从左到右依次滚动显示0~7,程序通过每次仅循环选通一只数码管*/#include #include #define uchar unsigned char #define uint unsigned intuchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //延时void DelayMS(uint x){uchar t;while(x--) for(t=0;t<120;t++);}//主程序void main(){uchar i,wei=0x80;while(1){for(i=0;i<8;i++){P2=0xff;//关闭显示wei=_crol_(wei,1);P0=DSY_CODE[i];//发送数字段码P2=wei;//发送位码DelayMS(300);}}}8 8 只数码管动态显示多个不同字符电路如上图/*名称:8 只数码管动态显示多个不同字符说明:数码管动态扫描显示 0~7。*/#include#include#define uchar unsigned char#define uint unsigned intuchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //延时void DelayMS(uint x){uchar t;while(x--) for(t=0;t<120;t++);}//主程序void main(){uchar i,wei=0x80;while(1){for(i=0;i<8;i++){P0=0xff;P0=DSY_CODE[i];//发送段码wei=_crol_(wei,1);P2=wei;//发送位码DelayMS(2);}}}
8 8 只数码管闪烁显示数字串
电路如上图
/*名称:8 只数码管闪烁显示数字串说明:数码管闪烁显示由 0~7 构成的一串数字本例用动态刷新法显示一串数字,在停止刷新时所有数字显示消失。*/#include#define uchar unsigned char#define uint unsigned int//段码表uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //位码表uchar code DSY_IDX[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //延时void DelayMS(uint x){uchar t;while(x--) for(t=0;t<120;t++);}//主程序void main(){uchar i,j;while(1){for(i=0;i<30;i++){for(j=0;j<8;j++){P0=0xff;P0=DSY_CODE[j];//发送段码P2=DSY_IDX[j];//发送位码DelayMS(2);}}P2=0x00;//关闭所有数码管并延时DelayMS(1000);}}
9 8 只数码管滚动显示数字串
电路如上图
/*名称:8 只数码管滚动显示数字串说明:数码管向左滚动显示 3 个字符构成的数字串*/#include#include#define uchar unsigned char#define uint unsigned int//段码表uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //下面数组看作环形队列,显示从某个数开始的 8 个数(10 表示黑屏)uchar Num[]={10,10,10,10,10,10,10,10,2,9,8};//延时void DelayMS(uint x){uchar t;while(x--) for(t=0;t<120;t++);}//主程序void main(){uchar i,j,k=0,m=0x80;while(1){ //刷新若干次,保持一段时间的稳定显示 for(i=0;i<15;i++){for(j=0;j<8;j++){ //发送段码,采用环形取法,从第 k 个开始取第 j 个 P0=0xff;P0=DSY_CODE[Num[(k+j)%11]]; m=_crol_(m,1);P2=m;//发送位码DelayMS(2);}}k=(k+1)%11; //环形队列首支针 k 递增,Num 下标范围 0~10,故对 11 取余}}11K1-K4 控制 LED 移位/*名称:K1-K4 控制 LED 移位说明:按下 K1 时,P0 口 LED 上移一位;按下 K2 时,P0 口 LED 下移一位;按下 K3 时,P2 口 LED 上移一位;按下 K4 时,P2 口 LED 下移一位;*/
![2df6b61269fb1d3baa0f26aacc83deba.png](https://i-blog.csdnimg.cn/blog_migrate/28d98a9419b968c79cb1768f446e070e.jpeg)
#include #include #define uchar unsigned char #define uint unsigned int //延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++); }· 根据 P1 口的按键移动LEDvoid Move_LED(){}//主程序void main(){uchar Recent_Key; //最近按键P0=0xfe;P2=0xfe;P1=0xff;Recent_Key=0xff;while(1){if(Recent_Key!=P1){Recent_Key=P1;//保存最近按键Move_LED();DelayMS(10);}}}12 K1-K4 按键状态显示/*名称:K1-K4 按键状态显示说明:K1、K2 按下时 LED 点亮,松开时熄灭,K3、K4 按下并释放时 LED 点亮,再次按下并释放时熄灭;*/
![ab4454ad63095f85ddc6a127cda3b557.png](https://i-blog.csdnimg.cn/blog_migrate/592be0ac43573e7c303e0c9fd1fa8cdd.jpeg)
#include#define uchar unsigned char #define uint unsigned int sbit LED1=P0^0;sbit LED2=P0^1; sbit LED3=P0^2; sbit LED4=P0^3; sbit K1=P1^0; sbit K2=P1^1; sbit K3=P1^2; sbit K4=P1^3; //延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++);}//主程序void main(){P0=0xff;P1=0xff;while(1){LED1=K1;LED2=K2;if(K3==0){while(K3==0);LED3=~LED3;}if(K4==0){while(K4==0);LED4=~LED4;}DelayMS(10);}}13K1-K4 分组控制 LED/*名称:K1-K4 分组控制 LED说明:每次按下 K1 时递增点亮一只 LED,全亮时再次按下则再次循环开始,K2 按下后点亮上面 4 只 LED,K3 按下后点亮下面 4 只 LED,K4 按下后关闭所有 LED*/
![4f89a6fe3ddd6a102910601bfdbf4ab2.png](https://i-blog.csdnimg.cn/blog_migrate/f11cb92daa0682e0f634620110d45f93.jpeg)
#include#define uchar unsigned char #define uint unsigned int //延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++);}//主程序void main(){uchar k,t,Key_State;P0=0xff;P1=0xff;while(1){t=P1;if(t!=0xff){DelayMS(10);if(t!=P1) continue;//取得 4 位按键值,由模式 XXXX1111(X 中有一位为 0,其他均为 1)//变为模式 0000XXXX(X 中有一位为 1,其他均为 0)Key_State=~t>>4;k=0;//检查 1 所在位置,累加获取按键号 kwhile(Key_State!=0){k++;Key_State>>=1;}//根据按键号 k 进行 4 种处理switch(k){case 1:if(P0==0x00) P0=0xff;P0<<=1;DelayMS(200);break;case 2:P0=0xf0;break;case 3:P0=0x0f;break;case 4:P0=0xff;}}}}14 K1-K4 控制数码管移位显示/*名称:K1-K4 控制数码管移位显示说明:按下 K1 时加 1 计数并增加显示位,按下 K2 时减 1 计数并减少显示位,按下 K3 时清零。*/#include#define uchar unsigned char#define uint unsigned int//段码uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //位码uchar code DSY_Index[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //待显示到各数码管的数字缓冲(开始仅在 0 位显示 0,其他黑屏) uchar Display_Buffer[]={0,10,10,10,10,10,10,10}; //延时void DelayMS(uint x){
![ef121f78f90d6a5995f1b6f15de30ebc.png](https://i-blog.csdnimg.cn/blog_migrate/c9bb38d0a005f0de3d4d6b9765394a8c.jpeg)
uchar i;while(x--) for(i=0;i<120;i++);}void Show_Count_ON_DSY(){uchar i;for(i=0;i<8;i++){P0=0xff;P0=DSY_CODE[Display_Buffer[i]]; P2=DSY_Index[i]; DelayMS(2);}}//主程序void main(){uchar i,Key_NO,Key_Counts=0;P0=0xff;P1=0xff;P2=0x00;while(1){Show_Count_ON_DSY();P1=0xff;Key_NO=P1;//P1 口按键状态分别为 K1-0xfe,K2-0xfd,K3-0xfbswitch(Key_NO){case 0xfe:Key_Counts++;if(Key_Counts>8) Key_Counts=8;Display_Buffer[Key_Counts-1]=Key_Counts;break;case 0xfd:if(Key_Counts>0)Display_Buffer[--Key_Counts]=10; break;case 0xfb:Display_Buffer[0]=0;for(i=1;i<8;i++) Display_Buffer[i]=10;Key_Counts=0;}//若键未释放则仅刷新显示,不进行键扫描while(P1!=0xff) Show_Count_ON_DSY();}
![76c4690f183181e8cb9a40b9e77eb514.png](https://i-blog.csdnimg.cn/blog_migrate/58e0541c87b6a9b49cf11b6b871fb687.jpeg)
}15 K1-K4 控制数码管加减演示/*名称:K1-K4 控制数码管加减演示说明:按下 K1 后加 1 计数,按下 K2 后减 1 计数,按下 K3 后清零。*/
#include #include #define uchar unsigned char #define uint unsigned int //段码uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //待显示的 3 位缓冲uchar Num_Buffer[]={0,0,0};//按键代码,按键计数uchar Key_Code,Key_Counts=0;//延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++);}//显示函数void Show_Counts_ON_DSY(){uchar i,j=0x01;Num_Buffer[2]=Key_Counts/100;Num_Buffer[1]=Key_Counts/10%10;Num_Buffer[0]=Key_Counts%10;for(i=0;i<3;i++){j=_cror_(j,1);P0=0xff;P0=DSY_CODE[Num_Buffer[i]];P2=j;DelayMS(1);}}//主程序void main(){uchar i;P0=0xff;P1=0xff;P2=0x00;Key_Code=0xff;while(1){Show_Counts_ON_DSY();P1=0xff;Key_Code=P1;//有键按下时,数码管刷新显示 30 次,该行代码同时起到延时作用 if(Key_Code!=0xff)for(i=0;i<30;i++) Show_Counts_ON_DSY();switch(Key_Code){case 0xfe:case 0xfd:case 0xfb:if(Key_Counts<255) Key_Counts++;break;if(Key_Counts>0) Key_Counts--;break;Key_Counts=0;}Key_Code=0xff;}
}
16 4X4 矩阵键盘控制条形 LED 显示
![911240f1d1bf4e95068c5fddf1b4f5bf.png](https://i-blog.csdnimg.cn/blog_migrate/eb273bed648dfacb8cf4c23277e31907.jpeg)
/* 名称:4X4 矩阵键盘控制条形 LED 显示说明:运行本例时,按下的按键值越大点亮的LED 越多。*/#include #include #define uchar unsigned char #define uint unsigned int //矩阵键盘按键特征码表uchar code KeyCodeTable[]={0x11,0x12,0x14,0x18,0x21, 0x22,0x24,0x28,0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88}; //延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++);}//键盘扫描uchar Keys_Scan(){uchar sCode,kCode,i,k;//低 4 位置 0,放入 4 行P1=0xf0;//若高 4 位出现 0,则有键按下if((P1&0xf0)!=0xf0){DelayMS(2);if((P1&0xf0)!=0xf0){sCode=0xfe;//行扫描码初值for(k=0;k<4;k++)//对 4 行分别进行扫描{P1=sCode;if((P1&0xf0)!=0xf0){kCode=~P1;for(i=0;i<16;i++)//查表得到按键序号并返回if(kCode==KeyCodeTable[i])return(i);}elsesCode=_crol_(sCode,1);}}}return(-1);}//主程序void main(){uchar i,P2_LED,P3_LED;uchar KeyNo=-1;//按键序号,-1 表示无按键while(1){KeyNo=Keys_Scan();//扫描键盘获取按键序号 KeyNoif(KeyNo!=-1){P2_LED=0xff;P3_LED=0xff;for(i=0;i<=KeyNo;i++) //键值越大,点亮的 LED 越多{if(i<8)P3_LED>>=1;elseP2_LED>>=1;}P3=P3_LED;//点亮条形 LEDP2=P2_LED;}
![399629ebc5680c29b5699c9c52e7648e.png](https://i-blog.csdnimg.cn/blog_migrate/6b6a4bfd3c4dac244fa4f07b2fef3aaf.jpeg)
}}
17 数码管显示 4X4 矩阵键盘按
键号/* 名称:数码管显示 4X4 矩阵键盘按键号说明:按下任意键时,数码管都会显示其键的序号,扫描程序首先判断按键发生在哪一列,然后根据所发生的行附加不同的值,从而得到按键的序号。*/
#include#define uchar unsigned char#define uint unsigned int//段码uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x88,0x83,0xc6,0xa1,0x86,0x8e,0x00};sbit BEEP=P3^7;//上次按键和当前按键的序号,该矩阵中序号范围 0~15,16 表示无按键uchar Pre_KeyNo=16,KeyNo=16;//延时void DelayMS(uint x){uchar i;while(x--) for(i=0;i<120;i++);}//矩阵键盘扫描void Keys_Scan(){uchar Tmp;P1=0x0f; //高 4 位置 0,放入 4 行DelayMS(1);Tmp=P1^0x0f;//按键后 0f 变成 0000XXXX,X 中一个为 0,3 个仍为 1,通过异或把 3 个 1 变为 0,唯一的 0 变为 1switch(Tmp)//判断按键发生于 0~3 列的哪一列{case 1:KeyNo=0;break;case 2:KeyNo=1;break;case 4: KeyNo=2;break;case 8:KeyNo=3;break;default:KeyNo=16; //无键按下}P1=0xf0;//低 4 位置 0,放入 4 列DelayMS(1);Tmp=P1>>4^0x0f;//按键后 f0 变成 XXXX0000,X 中有 1 个为 0,三个仍为 1;高 4 位转移到低 4 位并异或得到改变的值switch(Tmp)//对 0~3 行分别附加起始值 0,4,8,12{case 1:KeyNo+=0;break;case 2:KeyNo+=4;break;case 4:KeyNo+=8;break;case 8:KeyNo+=12;}}//蜂鸣器void Beep(){uchar i;for(i=0;i<100;i++){DelayMS(1);BEEP=~BEEP;}BEEP=0;}//主程序void main(){P0=0x00;BEEP=0;while(1){P1=0xf0;if(P1!=0xf0) Keys_Scan();//获取键序号if(Pre_KeyNo!=KeyNo){P0=~DSY_CODE[KeyNo];Beep();Pre_KeyNo=KeyNo;}DelayMS(100);}}
18 开关控制 LED
![9a943843bd48f234e4dba7a379ee5c88.png](https://i-blog.csdnimg.cn/blog_migrate/005d7677d472c310822bc944e992d175.jpeg)
/*名称:开关控制 LED说明:开关 S1 和 S2 分别控· LED1 和 LED2。*/#include sbit S1=P1^0; sbit S2=P1^1; sbit LED1=P0^0; sbit LED2=P0^1; //主程序void main(){while(1){LED1=S1;LED2=S2;}
![81dad2a966a307abd365668274ea1e07.png](https://i-blog.csdnimg.cn/blog_migrate/5068fa90dc8a356b98861d31260552aa.jpeg)
}
{BEEP=~BEEP;DelayMS(t);}BEEP=0;}
![2db39f97a6b2d012150949b3ed93982a.png](https://i-blog.csdnimg.cn/blog_migrate/46c91dbafc8be4ec4b28f601652be3ae.jpeg)
void main(){P1=0xff;BEEP=0;while(1){if(K1==0) Play(1); if(K2==0) Play(2); if(K3==0) Play(3); if(K4==0) Play(4);}}
46 单片机之间双向通信
/*名称:甲机串口程序
说明:甲机向乙机发送控制命令字符,甲机同时接收乙机发送的数字,并显示在数码管上。
*/
#include#define uchar unsigned char #define uint unsigned int sbit LED1=P1^0;sbit LED2=P1^3;sbit K1=P1^7;uchar Operation_No=0; //操作代码//数码管代码uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //延时void DelayMS(uint ms){uchar i;while(ms--) for(i=0;i<120;i++);}//向串口发送字符void Putc_to_SerialPort(uchar c){SBUF=c;while(TI==0);TI=0;}//主程序void main(){LED1=LED2=1;P0=0x00;SCON=0x50;//串口模式 1,允许接收TMOD=0x20;//T1 工作模式 2PCON=0x00;//波特率不倍增TH1=0xfd;TL1=0xfd;TI=RI=0;TR1=1;IE=0x90;//允许串口中断while(1){DelayMS(100);if(K1==0)//按下 K1 时选择操作代码 0,1,2,3{while(K1==0);Operation_No=(Operation_No+1)%4;switch(Operation_No)//根据操作代码发送 A/B/C 或停止发送{case 0:Putc_to_SerialPort('X');LED1=LED2=1;break;case 1:Putc_to_SerialPort('A');LED1=~LED1;LED2=1;break;case 2:Putc_to_SerialPort('B');LED2=~LED2;LED1=1;break;case 3:Putc_to_SerialPort('C');LED1=~LED1;LED2=LED1;break;}}}}//甲机串口接收中断函数void Serial_INT() interrupt4{if(RI){RI=0;if(SBUF>=0&&SBUF<=9) P0=DSY_CODE[SBUF];else P0=0x00;}}/*名称:乙机程序接收甲机发送字符并完成相应动作说明:乙机接收到甲机发送的信号后,根据相应信号控制 LED 完成不同闪烁动作。*/#include#define uchar unsigned char#define uint unsigned intsbit LED1=P1^0;sbit LED2=P1^3;sbit K2=P1^7;uchar NumX=-1;//延时void DelayMS(uint ms){uchar i;while(ms--) for(i=0;i<120;i++);}//主程序void main(){LED1=LED2=1; SCON=0x50; TMOD=0x20;//串口模式 1,允许接收//T1 工作模式 2TH1=0xfd;//波特率 9600TL1=0xfd;PCON=0x00;//波特率不倍增RI=TI=0;TR1=1;IE=0x90;while(1){DelayMS(100);if(K2==0){while(K2==0);NumX=++NumX%11;//产生 0~10 范围内的数字,其中 10 表示关闭SBUF=NumX;while(TI==0);TI=0;}}}void Serial_INT() interrupt 4{if(RI)//如收到则 LED 则动作{RI=0;switch(SBUF) //根据所收到的不同命令字符完成不同动作{}
![99202d450218ff04655dcaae14c7c223.png](https://i-blog.csdnimg.cn/blog_migrate/df5b9c4a7c46a4587a9cc78817a3ef34.jpeg)
}
}
47 单片机向主机发送字符串
/*名称:单片机向主机发送字符串说明:单片机按一定的时间间隔向主机发送字符串,发送内容在虚拟终端显示。*/#include#define uchar unsigned char #define uint unsigned int //延时void DelayMS(uint ms){uchar i;while(ms--) for(i=0;i<120;i++);}//向串口发送字符void Putc_to_SerialPort(uchar c){SBUF=c;while(TI==0);TI=0;}//向串口发送字符串void Puts_to_SerialPort(uchar *s){while(*s!='0'){Putc_to_SerialPort(*s);s++;DelayMS(5);}}//主程序void main(){uchar c=0;SCON=0x40;//串口模式 1TMOD=0x20;//T1 工作模式 2TH1=0xfd;//波特率 9600TL1=0xfd;PCON=0x00;//波特率不倍增TI=0;TR1=1;DelayMS(200);//向主机发送数据Puts_to_SerialPort("Receiving From 8051...");Puts_to_SerialPort("-------------------------------");DelayMS(50);while(1){Putc_to_SerialPort(c+'A');DelayMS(100);Putc_to_SerialPort(' ');DelayMS(100);if(c==25) //每输出一遍后加横线{Puts_to_SerialPort("-------------------------------");DelayMS(100);}c=(c+1)%26;if(c%10==0){//每输出 10 个字符后换行Puts_to_SerialPort("");DelayMS(100);
![be260666d27ff18884bf50de0614307b.png](https://i-blog.csdnimg.cn/blog_migrate/c468aef729eda050980667e4b6057100.jpeg)
}}}
48 单片机与 PC 通信
/*名称:单片机与 PC 通信说明:单片机可接收 PC 发送的数字字符,按下单片机的 K1 键后,单片机可向 PC 发送字符串。在 Proteus 环境下完成本实验时,需要安装 Virtual Serial Port Driver 和串口调试助手。本例缓冲 100 个数字字符,缓冲满后新数字从前面开始存放(环形缓冲)。*/#include#define uchar unsigned char#define uint unsigned intuchar Receive_Buffer[101];uchar Buf_Index=0;//数码管编码//接收缓冲//缓冲空间索引uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00}; //延时void DelayMS(uint ms){uchar i;while(ms--) for(i=0;i<120;i++);}//主程序void main(){uchar i;P0=0x00;Receive_Buffer[0]=-1;SCON=0x50;//串口模式 1,允许接收TMOD=0x20; TH1=0xfd; TL1=0xfd;//T1 工作模式 2//波特率 9600PCON=0x00;//波特率不倍增EA=1;EX0=1;IT0=1;ES=1;IP=0x01;TR1=1;while(1){for(i=0;i<100;i++){ //收到-1 为一次显示结束 if(Receive_Buffer[i]==-1) break; P0=DSY_CODE[Receive_Buffer[i]];DelayMS(200);}DelayMS(200);}}//串口接收中断函数void Serial_INT() interrupt 4{uchar c;if(RI==0) return;ES=0;//关闭串口中断RI=0;//清接收中断标志c=SBUF;if(c>='0'&&c<='9'){ //缓存新接收的每个字符,并在其后放-1 为结束标志Receive_Buffer[Buf_Index]=c-'0'; Receive_Buffer[Buf_Index+1]=-1; Buf_Index=(Buf_Index+1)%100;}ES=1;}void EX_INT0() interrupt 0//外部中断 0{uchar *s="这是由 8051 发送的字符串!";uchar i=0;while(s[i]!='0'){SBUF=s[i];while(TI==0);TI=0;i++;}}
第 02 篇硬件应用
19用 ADC0808 控制 PWM 输出
/*名称:用 ADC0808 控制 PWM 输出
说明:使用数模转换芯片 ADC0808,通过调节可变电阻 RV1 来调节脉冲宽度,运行程序时,通过虚拟示波器观察占空比的变化。
*/
![e9ff0e44d8d57bb921ceb7f03fb2e058.png](https://i-blog.csdnimg.cn/blog_migrate/04769556dbeb345a1c2bf2acbbfec460.jpeg)
#include#define uchar unsigned char #define uint unsigned intsbit CLK=P2^4;//时钟信号sbit ST=P2^5; sbit EOC=P2^6;//启动信号//转换结束信号sbit OE=P2^7; sbit PWM=P3^0;//输出使能//PWM 输出//延时void DelayMS(uint ms){uchar i;while(ms--) for(i=0;i<40;i++);}//主程序void main(){uchar Val;TMOD=0x02;//T1 工作模式 2TH0=0x14;TL0=0x00;IE=0x82;TR0=1;while(1){ST=0;ST=1;ST=0;//启动 A/D 转换while(!EOC);//等待转换完成OE=1;Val=P1;//读转换值OE=0;if(Val==0)//PWM 输出(占空比为 0%){PWM=0;DelayMS(0xff);continue;}if(Val==0xff)//PWM 输出(占空比为 100%){PWM=1;DelayMS(0xff);continue;}PWM=1;//PWM 输出(占空比为 0%~100%)DelayMS(Val);PWM=0;DelayMS(0xff-Val);}}//T0 定时器中断给 ADC0808 提供时钟信号void Timer0_INT() interrupt 1
![00dd1a5dd3d0faa346fb563323280123.png](https://i-blog.csdnimg.cn/blog_migrate/f100ef1d8ed533b304d4a549bc41dbcc.jpeg)
{CLK=~CLK;}
20ADC0809 数模转换与显示
/*名称:ADC0809 数模转换与显示说明:ADC0809 采样通道 3 输入的模拟量,转换后的结果显示在数码管上。*/#include#define uchar unsigned char#define uint unsigned int//各数字的数码管段码(共阴)uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};sbit CLK=P1^3;//时钟信号sbit ST=P1^2;//启动信号sbit EOC=P1^1;//转换结束信号sbit OE=P1^0;//输出使能//延时void DelayMS(uint ms){uchar i;while(ms--) for(i=0;i<120;i++);}//显示转换结果void Display_Result(uchar d){P2=0xf7;//第 4 个数码管显示个位数P0=DSY_CODE[d%10];DelayMS(5);P2=0xfb;//第 3 个数码管显示十位数P0=DSY_CODE[d%100/10];DelayMS(5);P2=0xfd;//第 2 个数码管显示百位数P0=DSY_CODE[d/100];DelayMS(5);}//主程序void main(){TMOD=0x02;//T1 工作模式 2TH0=0x14;TL0=0x00;IE=0x82;TR0=1;P1=0x3f;//选择 ADC0809 的通道 3(0111)(P1.4~P1.6)while(1){ST=0;ST=1;ST=0; while(EOC==0);//启动 A/D 转换//等待转换完成OE=1;Display_Result(P3);OE=0;}}//T0 定时器中断给 ADC0808 提供时钟信号void Timer0_INT() interrupt 1{CLK=~CLK;}