开发网站能赚多少钱,wordpress 修改搜索引擎,火山开发软件可以开发网站吗,wordpress 内部标签前言
本篇文章属于学习笔记#xff0c;来源于B站教学视频#xff0c;相关代码工程请从源地址自行下载。这位Up讲解得很好#xff0c;适合同学们一起学习#xff0c;在这里推荐给大家。本文为个人学习笔记#xff0c;只能做参考#xff0c;细节方面建议观看视频#xff…前言
本篇文章属于学习笔记来源于B站教学视频相关代码工程请从源地址自行下载。这位Up讲解得很好适合同学们一起学习在这里推荐给大家。本文为个人学习笔记只能做参考细节方面建议观看视频肯定受益匪浅。
51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Mb411e7re?p1
一、环境搭建 1、开发软件Keil5C51 2、烧录软件stc-isp 3、普中51单片机开发板 二、单片机介绍
1、单片机Micro Controller Unit 即MCU
2、本篇所使用的单片机为STC89C52单片机
所属系列为8051即51单片机。8051最开始指在80年代生产的8051内核的单片机。后延伸为只要是8051内核的单片机都统称为51单片机。
3、51单片机命名规则 4、51单片机结构 三、单片机实操一点亮一个LED
1、打开STC-ISP添加芯片包到开发环境 2、创建工程 3、创建文件 4、LED的硬件原理图
在下面的图中我们可以看到LED最终连上了单片机的管脚。而单片机需要通过CPU控制寄存器的值进而通过驱动器加大控制力度由控制电路输出高低电平对应寄存器1/0。因此程序需要在对应的寄存器上写1或0即可控制LED的亮灭。 5、编写程序
根据硬件原理图和寄存器定义来对操作寄存器地址实现灯的点亮
#include STC89C5xRC.Hvoid main()
{P2 0xFE; //1111 1110
}
6、实验过程与代码解释
1点击F7编译单个文件编译失败给出P2不认识的提示 2添加H文件继续编译编译通过 说明头文件定义了P2 3为什么控制的是P2因为硬件原理图以及头文件的定义拉低电平即可点亮一盏灯 7、生成文件下载到板子上重新上电之后可运行该程序 四、单片机实操二LED闪烁
1、在指定路径下创建工程并添加新文件
2、通过STC-ISP拷贝延时代码 3、编写程序
加入延时方便观察灯的闪烁
#include STC89C5xRC.H
#include INTRINS.Hvoid Delay500ms() //12.000MHz
{unsigned char i, j, k;_nop_(); //An empty function, from INTRINS.Hi 4;j 205;k 187;do{do{while (--k);} while (--j);} while (--i);
}void main()
{P20xFE;Delay500ms();P20xFF;Delay500ms();
}
4、实验过程 五、单片机实操三LED流水灯
1、在指定路径下创建工程并添加新文件
2、编写程序
让LED循环点亮像流水一样
#include STC89C5xRC.H
#include INTRINS.Hvoid Delay500ms() //12.000MHz
{unsigned char i, j, k;_nop_();i 4;j 205;k 187;do{do{while (--k);} while (--j);} while (--i);
}void main()
{while(1){P20xFE; //1111 1110Delay500ms();P20xFD; //1111 1101Delay500ms();P20xFB; //1111 1011Delay500ms();P20xF7; //1111 0111Delay500ms();P20xEF; //1110 1111Delay500ms();P20xDF; //1101 1111Delay500ms();P20xBF; //1011 1111Delay500ms();P20x7F; //0111 1111Delay500ms();}
}
六、单片机实操四LED流水灯Plus
1、在指定路径下创建工程并添加新文件
2、编写程序
将延时函数参数化。
#include STC89C5xRC.H
#include INTRINS.Hvoid Delayxms(unsigned int xms) //12.000MHz
{unsigned char i, j;while(xms){i 2;j 239;do{while (--j);} while (--i);xms--; //xmsxms-1}
}void main()
{while(1){P20xFE; //1111 1110Delayxms(500);P20xFD; //1111 1101Delayxms(500);P20xFB; //1111 1011Delayxms(500);P20xF7; //1111 0111Delayxms(500);P20xEF; //1110 1111Delayxms(500);P20xDF; //1101 1111Delayxms(500);P20xBF; //1011 1111Delayxms(500);P20x7F; //0111 1111Delayxms(500);}
}
3、51单片机的数据类型
我们在上面的程序中使用到了数据类型unsigned int xms即xms在单片机中能表示0~65535 七、单片机实操五独立按键控制LED灯亮灭
1、在指定路径下创建工程并添加新文件
2、独立按键原理图 3、编写程序
按下按键亮灯松开按键灭灯。
#include STC89C5xRC.Hvoid main()
{while(1){if(P300){P200;}else{P201;}}
}
4、51单片机数据运算
上述代码中我们使用到了这个运算符表示等于。 5、51单片机基本语句
上述程序用到了if语句通过判断按键的动作来实现灯的亮灭 6、注意事项
程序写的是P30独立按键根据原理图需要按下K2才能点亮第一盏灯。原理图设计者并没有按照顺序一一对应按键这是设计者埋下的小坑
P30是H文件中定义的如果是其他H文件可能没有或者用另一个变量表示这个时候需要你自己去写或者更改变量 八、单片机实操六独立按键控制LED灯状态
1、在指定路径下创建工程并添加新文件
2、编写程序
按键消抖检测松手才改变LED灯的状态使其松开按键后长亮或长灭。
#include STC89C5xRC.Hvoid Delay(unsigned int xms) //12.000MHz
{unsigned char i, j;while(xms){i 2;j 239;do{while (--j);} while (--i);xms--;}
}void main()
{while(1){if(P310){Delay(20); // Keys away shakingwhile(P310);Delay(20); // Detection of let goP20~P20;}}
} 九、单片机实操七独立按键控制LED显示二进制
1、在指定路径下创建工程并添加新文件
2、编写程序
通过不停的按下按键使得灯以二进制的方式不断往上加一达到用灯来表示按键次数
#include STC89C5xRC.Hvoid Delay(unsigned int xms) //12.000MHz
{unsigned char i, j;while(xms){i 2;j 239;do{while (--j);} while (--i);xms--;}
}void main()
{unsigned char LEDNum0; // char max num is 255while(1){if(P310){Delay(20);while(P310);Delay(20);LEDNum;P2~LEDNum;}}
} 十、单片机实操八独立按键控制LED移位
1、在指定路径下创建工程并添加新文件
2、编写程序
按下P31往左边移一位按下P30往右边移一位以LED灯来展示。
#include STC89C5xRC.H
void Delay(unsigned int xms); // must statementunsigned char LEDNum; // The global variablevoid main()
{P2~0x01; //int P2while(1){if(P310){Delay(20);while(P310);Delay(20);LEDNum;if(LEDNum8)LEDNum0;P2~(0x01LEDNum); // 0x01 of P2 need shift to the left LEDNum, and get the not}if(P300){Delay(20);while(P300);Delay(20);if(LEDNum0)LEDNum7;elseLEDNum--;P2~(0x01LEDNum);}}
}void Delay(unsigned int xms) //12.000MHz
{unsigned char i, j;while(xms){i 2;j 239;do{while (--j);} while (--i);xms--;}
}
十一、单片机实操九静态数码管显示
1、在指定路径下创建工程并添加新文件
2、单个数码管引脚定义
数码管的接法有共阳和共阴之分。共阴时拉高电压即可点亮。共阳时拉低电平点亮。 3、开发板四位一体的数码管引脚定义 4、硬件原理图
138译码器控制数码管使能使用3个单片机输入控制8个数码管显示每个数字的一个笔画由双向数据缓存器245单片机输出能力有限需要该芯片提高输入能力控制亮灭。
因此首先控制P22~P24来选中数码管然后选中数码管的笔画最终呈现数据。 5、C51单片机数组 6、C51单片机子函数 7、数码管段码表共阴极电路共阳极则不一样 8、编写程序
#include STC89C5xRC.Hunsigned char NixieTable[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71, 0x00};void Nixie(unsigned char Location,Number)
{switch(Location){case 1:P241;P231;P221;break;case 2:P241;P231;P220;break;case 3:P241;P230;P221;break;case 4:P241;P230;P220;break;case 5:P240;P231;P221;break;case 6:P240;P231;P220;break;case 7:P240;P230;P221;break;case 8:P240;P230;P220;break;}P0NixieTable[Number];
}void main()
{
// P241; //Controls a nixie tube
// P230;
// P221;
// P00x7D; //value is 6Nixie(2,3);while(1){}
}
十二、单片机实操十动态数码管显示
1、在指定路径下创建工程并添加新文件
2、编写程序
动态清零数字消影来实现动态数码管显示这是单片机不断扫描来成像的将耗费大量CPU资源。因此硬件电路一般会加1640的芯片来驱动将大量减少扫描带来的CPU损耗。
#include STC89C5xRC.Hunsigned char NixieTable[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71, 0x00};void Delay(unsigned int xms) //12.000MHz
{unsigned char i, j;while(xms){i 2;j 239;do{while (--j);} while (--i);xms--;}
}void Nixie(unsigned char Location,Number)
{switch(Location){case 1:P241;P231;P221;break;case 2:P241;P231;P220;break;case 3:P241;P230;P221;break;case 4:P241;P230;P220;break;case 5:P240;P231;P221;break;case 6:P240;P231;P220;break;case 7:P240;P230;P221;break;case 8:P240;P230;P220;break;}P0NixieTable[Number];Delay(1); // Shadow eliminationP00x00; // reset
}void main()
{while(1){Nixie(1,1);Nixie(2,2);Nixie(3,3);}
}
十三、单片机实操十一模块化编程
1、在指定路径下创建工程并添加新文件
2、模块化编程 3、模块化编程框图 4、模块化编程注意事项 5、C预编译 6、增加中文注释 7、编写代码
main.c
#include STC89C5xRC.H
#include Delay.h // 使用双引号优先查询工程目录
#include Nixie.h void main()
{while(1){Nixie(1,1);Nixie(2,2);Nixie(3,3);}
}
Delay.c
void Delay(unsigned int xms) //12.000MHz
{unsigned char i, j;while(xms){i 2;j 239;do{while (--j);} while (--i);xms--;}
}
Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__void Delay(unsigned int xms);#endif
Nixie.c
#include STC89C5xRC.H
#include Delay.hunsigned char NixieTable[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71, 0x00};void Nixie(unsigned char Location,Number)
{switch(Location){case 1:P241;P231;P221;break;case 2:P241;P231;P220;break;case 3:P241;P230;P221;break;case 4:P241;P230;P220;break;case 5:P240;P231;P221;break;case 6:P240;P231;P220;break;case 7:P240;P230;P221;break;case 8:P240;P230;P220;break;}P0NixieTable[Number];Delay(1); // Shadow eliminationP00x00; // reset
}
Nixie.h
#ifndef __NIXIE_H__
#define __NIXIE_H__void Nixie(unsigned char Location,Number);#endif
十四、单片机实操十二LCD1602调试工具
1、在指定路径下创建工程并添加新文件
2、LCD1602调试工具 3、编写程序
main.c
#include STC89C5xRC.H
#include LCD1602.hvoid main()
{LCD_Init();LCD_ShowChar(1,1,B);LCD_ShowString(1,3,Hello);LCD_ShowNum(1,9,123,3);LCD_ShowSignedNum(1,13,-66,2);LCD_ShowHexNum(2,1,0xA8,2);LCD_ShowBinNum(2,4,0xAA,8);LCD_ShowChar(2,13,A);while(1){}
} LCD1602.c
#include STC89C5xRC.H//引脚配置
sbit LCD_RSP2^6;
sbit LCD_RWP2^5;
sbit LCD_ENP2^7;
#define LCD_DataPort P0//函数定义
/*** brief LCD1602延时函数12MHz调用可延时1ms* param 无* retval 无*/
void LCD_Delay()
{unsigned char i, j;i 2;j 239;do{while (--j);} while (--i);
}/*** brief LCD1602写命令* param Command 要写入的命令* retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS0;LCD_RW0;LCD_DataPortCommand;LCD_EN1;LCD_Delay();LCD_EN0;LCD_Delay();
}/*** brief LCD1602写数据* param Data 要写入的数据* retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS1;LCD_RW0;LCD_DataPortData;LCD_EN1;LCD_Delay();LCD_EN0;LCD_Delay();
}/*** brief LCD1602设置光标位置* param Line 行位置范围1~2* param Column 列位置范围1~16* retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line1){LCD_WriteCommand(0x80|(Column-1));}else if(Line2){LCD_WriteCommand(0x80|(Column-10x40));}
}/*** brief LCD1602初始化函数* param 无* retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口两行显示5*7点阵LCD_WriteCommand(0x0c);//显示开光标关闪烁关LCD_WriteCommand(0x06);//数据读写操作后光标自动加一画面不动LCD_WriteCommand(0x01);//光标复位清屏
}/*** brief 在LCD1602指定位置上显示一个字符* param Line 行位置范围1~2* param Column 列位置范围1~16* param Char 要显示的字符* retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** brief 在LCD1602指定位置开始显示所给字符串* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param String 要显示的字符串* retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i0;String[i]!\0;i){LCD_WriteData(String[i]);}
}/*** brief 返回值X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result1;for(i0;iY;i){Result*X;}return Result;
}/*** brief 在LCD1602指定位置开始显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围0~65535* param Length 要显示数字的长度范围1~5* retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(iLength;i0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%100);}
}/*** brief 在LCD1602指定位置开始以有符号十进制显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围-32768~32767* param Length 要显示数字的长度范围1~5* retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number0){LCD_WriteData();Number1Number;}else{LCD_WriteData(-);Number1-Number;}for(iLength;i0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%100);}
}/*** brief 在LCD1602指定位置开始以十六进制显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围0~0xFFFF* param Length 要显示数字的长度范围1~4* retval 无*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(iLength;i0;i--){SingleNumberNumber/LCD_Pow(16,i-1)%16;if(SingleNumber10){LCD_WriteData(SingleNumber0);}else{LCD_WriteData(SingleNumber-10A);}}
}/*** brief 在LCD1602指定位置开始以二进制显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围0~1111 1111 1111 1111* param Length 要显示数字的长度范围1~16* retval 无*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(iLength;i0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%20);}
}LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__//用户调用函数
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif4、注意事项
单引号和双引号都有全角和半角之分全角的又叫中文字符半角的又称英文字符。在c语言中全角字符没有任何意义它就是一个普通字符没有含义半角字符才有不同的意义 双引号用来括起一个字符串如China; 单引号原来括起一个字符如f。 二者含义不同不能混用。 十五、单片机实操十三矩阵键盘
1、在指定路径下创建工程并添加新文件
2、矩阵键盘介绍 3、扫描的概念 4、硬件连线
我们想选取1、5、9、13即第一列可以先把P1全部置为高即全部拉高接着让P13拉低则选中了第一列。其他也这样操作。 5、编写程序
main.c
#include STC89C5xRC.H
#include LCD1602.h
#include Delay.h
#include MatrixKey.hunsigned char KeyNum;void main()
{LCD_Init();
// LCD_ShowChar(1,1,B);LCD_ShowString(1,3,MatrixKey:);
// LCD_ShowNum(1,9,123,3);
// LCD_ShowSignedNum(1,13,-66,2);
// LCD_ShowHexNum(2,1,0xA8,2);
// LCD_ShowBinNum(2,4,0xAA,8);
// LCD_ShowChar(2,13,A);while(1){KeyNumMatrixKey();if(KeyNum){LCD_ShowNum(2,3,KeyNum,2);}}
}
MatrixKey.c
#include STC89C5xRC.H
#include Delay.hunsigned char MatrixKey()
{unsigned char KeyNumber0;P10xFF;P130;if(P170){Delay(20);while(P170);Delay(20);KeyNumber1;}if(P160){Delay(20);while(P160);Delay(20);KeyNumber5;}if(P150){Delay(20);while(P150);Delay(20);KeyNumber9;}if(P140){Delay(20);while(P140);Delay(20);KeyNumber13;}P10xFF;P120;if(P170){Delay(20);while(P170);Delay(20);KeyNumber2;}if(P160){Delay(20);while(P160);Delay(20);KeyNumber6;}if(P150){Delay(20);while(P150);Delay(20);KeyNumber10;}if(P140){Delay(20);while(P140);Delay(20);KeyNumber14;}P10xFF;P110;if(P170){Delay(20);while(P170);Delay(20);KeyNumber3;}if(P160){Delay(20);while(P160);Delay(20);KeyNumber7;}if(P150){Delay(20);while(P150);Delay(20);KeyNumber11;}if(P140){Delay(20);while(P140);Delay(20);KeyNumber15;}P10xFF;P100;if(P170){Delay(20);while(P170);Delay(20);KeyNumber4;}if(P160){Delay(20);while(P160);Delay(20);KeyNumber8;}if(P150){Delay(20);while(P150);Delay(20);KeyNumber12;}if(P140){Delay(20);while(P140);Delay(20);KeyNumber16;}return KeyNumber;
}
MatrixKey.h
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__unsigned char MatrixKey();#endif
其它文件复制之前写的模块即可。
6、软件使用技巧配置模板 十六、单片机实操十四矩阵键盘密码锁
1、复制工程后打开 2、编写程序
main.c
#include STC89C5xRC.H
#include LCD1602.h
#include Delay.h
#include MatrixKey.hunsigned char KeyNum;
unsigned int Password, Count;void main()
{LCD_Init();
// LCD_ShowChar(1,1,B);LCD_ShowString(1,1,Password:);
// LCD_ShowNum(1,9,123,3);
// LCD_ShowSignedNum(1,13,-66,2);
// LCD_ShowHexNum(2,1,0xA8,2);
// LCD_ShowBinNum(2,4,0xAA,8);
// LCD_ShowChar(2,13,A);while(1){KeyNumMatrixKey();if(KeyNum){if(KeyNum10) // 如果S1~S10按键按下输入密码{if(Count4) // 密码四位数{Password*10; // 密码左移一位这样就可以依次输入密码PasswordKeyNum%10; // 获取一位密码加入到原密码,此时10为0Count;}}LCD_ShowNum(2,1,Password,4);if(KeyNum11) // 确认{if(Password1234){LCD_ShowString(1,14,OK );Password0;Count0;LCD_ShowNum(2,1,Password,4);}else{LCD_ShowString(1,14,ERR);Password0;Count0;LCD_ShowNum(2,1,Password,4);}}if(KeyNum12) //取消{Password0;Count0;LCD_ShowString(1,14, );LCD_ShowNum(2,1,Password,4);}}}
}
其它文件复制之前写的模块即可。 十七、单片机实操十五定时器与按键控制LED流水灯模式
1、定时器介绍 2、STC89C52定时器资源 3、定时器狂框图 4、定时器工作模式 5、中断系统 6、中断程序流程 7、STC89C52中断资源 8、定时器和中断系统 9、定时器相关寄存器 10、编写程序
通过独立按键控制流水灯模式并由定时器执行流水灯。
main.c
#include STC89C5xRC.H
#include Timer0.h
#include Key.h
#include INTRINS.Hunsigned char KeyNum,LEDMode;void main()
{P20xFE;Timer0Init();while(1){KeyNumKey(); //获取独立按键键码if(KeyNum) //如果按键按下{if(KeyNum1) //如果K1按键按下{LEDMode; //模式切换按1下按键是模式1按2下是模式0默认模式0if(LEDMode2)LEDMode0;}}}
}void Timer0_Routine() interrupt 1 //中断函数标识含优先级
{static unsigned int T0Count; //静态变量拥有局部作用域全局生命周期TL0 0x18; //设置定时初值TH0 0xFC; //设置定时初值T0Count; //T0Count计次对中断频率进行分频if(T0Count500)//分频500次500ms{T0Count0;if(LEDMode0) //模式判断P2_crol_(P2,1); //LED输出循环左移函数即使流水灯循环左移if(LEDMode1)P2_cror_(P2,1);}
}Timer0.c
#include STC89C5xRC.H/*** brief 定时器0初始化1毫秒12.000MHz* param 无* retval 无*/
void Timer0Init(void)
{TMOD 0xF0; //设置定时器模式只改变T0避免T1改变TMOD | 0x01; //设置定时器模式TL0 0x18; //高位设置定时初值 65535/256TH0 0xFC; //低位设置定时初值 65535%256TF0 0; //清除TF0标志TR0 1; //定时器0开始计时ET01;EA1;PT00;
}/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count; //静态变量拥有局部作用域全局生命周期TL0 0x18; //设置定时初值像沙漏重置沙漏时间TH0 0xFC; //设置定时初值T0Count;if(T0Count1000){T0Count0;}
}
*/Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0Init(void);#endifKey.c
#include STC89C5xRC.H
#include Delay.h/*** brief 获取独立按键键码* param 无* retval 按下按键的键码范围0~4无按键按下时返回值为0*/
unsigned char Key()
{unsigned char KeyNumber0;if(P310){Delay(20);while(P310);Delay(20);KeyNumber1;}if(P300){Delay(20);while(P300);Delay(20);KeyNumber2;}if(P320){Delay(20);while(P320);Delay(20);KeyNumber3;}if(P330){Delay(20);while(P330);Delay(20);KeyNumber4;}return KeyNumber;
}Key.h
#ifndef __KEY_H__
#define __KEY_H__unsigned char Key();#endif其它文件复制之前写的模块即可。
11、定时器代码获取 十八、单片机实操十六定时器时钟
1、编写程序
制作一个一天时间的计时器。
main.c
#include STC89C5xRC.H
#include Timer0.h
#include Delay.h
#include LCD1602.hunsigned char Sec, Min59, Hour23;void main()
{Timer0Init();LCD_Init();LCD_ShowString(1,1,Clock:);while(1){LCD_ShowNum(2,1,Hour,2);LCD_ShowString(2,3,:);LCD_ShowNum(2,4,Min,2);LCD_ShowString(2,6,:);LCD_ShowNum(2,7,Sec,2);}
}void Timer0_Routine() interrupt 1 //中断函数标识含优先级
{static unsigned int T0Count; //静态变量拥有局部作用域全局生命周期TL0 0x18; //设置定时初值TH0 0xFC; //设置定时初值T0Count; //T0Count计次对中断频率进行分频if(T0Count1000)//1000ms{T0Count0;Sec;if(Sec60){Sec0;Min;if(Min60){Min0;Hour;if(Hour24){Hour0;}}}}
}其它文件复制之前写的模块即可。
十九、单片机实操十七串口通信与串口向电脑发送数据
1、串口介绍 2、接口及引脚定义 3、硬件电路 4、电平标准 5、常见通信接口比较 6、相关术语 7、51单片机的UART 8、串口参数与时序图 9、串口模式图 10、串口相关寄存器 11、串口和中断系统 11、使用工具生成串口配置 12、编写程序
main.c
#include STC89C5xRC.H
#include Delay.h
#include UART.hunsigned char Sec;void main()
{UartInit();while(1){UART_SendByte(Sec);Sec;Delay(1); // 必要的延时避免误差导致乱码没误差的时候可以不需要}
}
UART.c
#include STC89C5xRC.Hvoid UartInit(void) //4800bps11.0592MHz
{PCON 0x80; //波特率不倍速SCON 0x40; //8位数据,可变波特率TMOD 0x0F; //设置定时器模式TMOD | 0x20; //设置定时器模式TL1 0xFA; //设置定时初始值TH1 0xFA; //设置定时重载值ET1 0; //禁止定时器%d中断TR1 1; //定时器1开始计时
}void UART_SendByte(unsigned char Byte)
{SBUFByte; // 根据硬件原理操作寄存器while(TI0); // 操作寄存器检测是否完成TI0; // 按要求重新赋值为0
}
UART.h
#ifndef __UART_H__
#define __UART_H__void UartInit(void);
void UART_SendByte(unsigned char Byte);#endif其他文件复制之前写的模块即可。
13、调试程序 二十、单片机实操十八电脑通过串口控制LED
1、编写程序
#include STC89C5xRC.H
#include Delay.h
#include UART.hunsigned char Sec;void main()
{UartInit();while(1){}
}void UART_Routine() interrupt 4
{if(RI1){P2~SBUF; // 读寄存器的数据UART_SendByte(SBUF);RI0; // 说明书要求手动复位}
}
其他文件复制之前写的模块即可。
2、波特率计算
1内部逻辑图 2配置的定时初值 3计算方式 F3243
256-24313us
每记13次数溢出1次;
1/130.0769230769230769MHz;
0.0769230769230769/160.0048076923076923MHz4,807.692307692308HZ
3、ASCII码编码表
文本模式与Hex模式对应情况。 二十一、单片机实操十九LED点阵屏与显示图形
1、LED点阵屏介绍 2、显示原理 3、74HC595模块原理图 4、74HC595介绍 5、接线
OE要通过跳线帽与GND相连而开发板默认OE与VCC相连因此需要操作。
6、开发板引脚对应关系 7、C51的sfr、sbit 8、编写程序
main.c
#include STC89C5xRC.H
#include Delay.Hsbit RCKP3^5; //RCLK
sbit SCKP3^6; //SRCLK
sbit SERP3^4; //SER#define MATRIX_LED_PORT P0void _74HC595_WriteByte(unsigned char Byte)
{
// SERByte0x80; //一般是0、1赋值不过如果非0都会当作1
// SCK1;
// SCK0;
// SERByte0x60;
// SCK1;
// SCK0;unsigned char i;for(i0;i8;i){SERByte(0x80i);SCK1;SCK0;}RCK1;RCK0;
}void MatrixLED_ShowColumn(unsigned char Column, Data)
{_74HC595_WriteByte(Data);
// if(Column0){P0~0x80;}
// if(Column1){P0~0x40;}MATRIX_LED_PORT~(0x80Column);Delay(1);MATRIX_LED_PORT0xFF;}void main()
{SCK0;RCK0;while(1){
// _74HC595_WriteByte(0xAA);MatrixLED_ShowColumn(0,0x80);MatrixLED_ShowColumn(1,0x40);MatrixLED_ShowColumn(2,0x20);MatrixLED_ShowColumn(3,0x10);}
}
二十二、单片机实操二十LED点阵屏显示动画
1、字模提取软件 取出数据如下将作为程序数组使用
0xFF,0x10,0x10,0x10,0xFF,0x00,0x1E,0x29,0x29,0x29,0x18,0x00,0xFE,0x01,0x02,0x00, 0xFE,0x01,0x02,0x00,0x0E,0x11,0x11,0x0E,0x00,0x7D,0x7D,0x00,0x00,0x00,0x00,0x00,
2、编写程序
main.c
#include STC89C5xRC.H
#include Delay.H
#include MatrixLED.Hunsigned char Animation[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 为了显示更好看,避免第一列直接显示字符本身
0xFF,0x10,0x10,0x10,0xFF,0x00,0x1E,0x29,0x29,0x29,0x18,0x00,0xFE,0x01,0x02,0x00,
0xFE,0x01,0x02,0x00,0x0E,0x11,0x11,0x0E,0x00,0x7D,0x7D,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 为了显示更好看
};void main()
{unsigned char i, Offset1, Count0;while(1){for(i0;i8;i){MatrixLED_ShowColumn(i,Animation[iOffset]);}Count;if(Count10){Count0;Offset;if(Offset40){Offset0; //防止数组溢出}}}
}
MatrixLED.c
#include STC89C5xRC.H
#include Delay.Hsbit RCKP3^5; //RCLK
sbit SCKP3^6; //SRCLK
sbit SERP3^4; //SER#define MATRIX_LED_PORT P0void _74HC595_WriteByte(unsigned char Byte)
{
// SERByte0x80; //一般是0、1赋值不过如果非0都会当作1
// SCK1;
// SCK0;
// SERByte0x60;
// SCK1;
// SCK0;unsigned char i;for(i0;i8;i){SERByte(0x80i);SCK1;SCK0;}RCK1;RCK0;
}void MatrixLED_Init()
{SCK0;RCK0;
}void MatrixLED_ShowColumn(unsigned char Column, Data)
{_74HC595_WriteByte(Data);
// if(Column0){P0~0x80;}
// if(Column1){P0~0x40;}MATRIX_LED_PORT~(0x80Column);Delay(1);MATRIX_LED_PORT0xFF;}MatrixLED.h
#ifndef __MATRIXLED_H__
#define __MATRIXLED_H__void MatrixLED_ShowColumn(unsigned char Column, Data);
void MatrixLED_Init();#endif3、注意事项
将数据放在flash里面用来避免内存被消耗过多但这种数据是不能更改的方法如下
将
unsigned char Animation[]
改为
unsigned char code Animation[]
二十三、单片机实操二十一DS1302实时时钟
1、DS1302介绍 2、引脚定义和应用电路 3、内部结构图 4、寄存器定义 5、时序定义 6、BCD码 7、编写代码
main.c
#include STC89C5xRC.H
#include LCD1602.h
#include DS1302.h// unsigned char Second, Minute;void main()
{LCD_Init();DS1302_Init();// DS1302_WriteByte(0x8E, 0x00); // 解除芯片写保护避免数值不动
// DS1302_WriteByte(0x80, 0x54);DS1302_SetTime();while(1){DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_TIME[0],2);LCD_ShowNum(1,4,DS1302_TIME[1],2);LCD_ShowNum(1,7,DS1302_TIME[2],2);LCD_ShowNum(2,1,DS1302_TIME[3],2);LCD_ShowNum(2,4,DS1302_TIME[4],2);LCD_ShowNum(2,7,DS1302_TIME[5],2);// SecondDS1302_ReadByte(0x81);
// MinuteDS1302_ReadByte(0x83);
// LCD_ShowNum(2,1,Second/16*10Second%16,2);
// LCD_ShowNum(2,3,Minute/16*10Minute%16,2);}
}
DS1302.c
#include STC89C5xRC.Hsbit DS1302_SCLKP3^6;
sbit DS1302_IOP3^4;
sbit DS1302_CEP3^5;#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8Eunsigned char DS1302_TIME[]{19,11,16,12,59,55,6};void DS1302_Init(void)
{DS1302_CE0;DS1302_SCLK0;
}void DS1302_WriteByte(unsigned char Command, Data)
{unsigned char i;DS1302_CE1;// DS1302_IOCommand0x01;
// DS1302_SCLK1; // 速度慢可以不加延时有些速度快的芯片需要增加延时
// DS1302_SCLK0;
//
// DS1302_IOCommand0x02;
// DS1302_SCLK1;
// DS1302_SCLK0;for(i0;i8;i){DS1302_IOCommand(0x01i);DS1302_SCLK1;DS1302_SCLK0;}for(i0;i8;i){DS1302_IOData(0x01i);DS1302_SCLK1;DS1302_SCLK0;}DS1302_CE0; //完成一次操作释放IO
}unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i,Data0x00;Command|0x01; //DS1302_CE1;for(i0;i8;i){DS1302_IOCommand(0x01i);DS1302_SCLK0; //根据时序操作DS1302_SCLK1;}
// DS1302_SCLK0;
// DS1302_SCLK1;
// if(DS1302_IO)
// {
// DataData|0x01;
// }
// DS1302_SCLK0;
// DS1302_SCLK1;
// if(DS1302_IO)
// {
// DataData|0x02;
// }for(i0;i8;i){DS1302_SCLK1; //重复置1是去掉一个周期为的是满足时序DS1302_SCLK0;if(DS1302_IO){Data|(0x01i);}}DS1302_CE0;DS1302_IO0; // 如果不加这一行将显示全0return Data;
}void DS1302_SetTime(void)
{DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_TIME[0]/10*16DS1302_TIME[0]%10);DS1302_WriteByte(DS1302_MONTH,DS1302_TIME[1]/10*16DS1302_TIME[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_TIME[2]/10*16DS1302_TIME[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_TIME[3]/10*16DS1302_TIME[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_TIME[4]/10*16DS1302_TIME[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_TIME[5]/10*16DS1302_TIME[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_TIME[6]/10*16DS1302_TIME[6]%10);DS1302_WriteByte(DS1302_WP,0x00);
}void DS1302_ReadTime(void)
{unsigned char Temp;TempDS1302_ReadByte(DS1302_YEAR);DS1302_TIME[0]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_MONTH);DS1302_TIME[1]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_DATE);DS1302_TIME[2]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_HOUR);DS1302_TIME[3]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_MINUTE);DS1302_TIME[4]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_SECOND);DS1302_TIME[5]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_DAY);DS1302_TIME[6]Temp/16*10Temp%16;
}
DS1302.h
#ifndef __DS1302_H__
#define __DS1302_H__extern unsigned char DS1302_TIME[]; // 声明数组void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command, Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);#endif二十四、单片机实操二十二DS1302可调时钟
1、编写程序
main.c
#include STC89C5xRC.H
#include LCD1602.h
#include DS1302.h
#include Key.h
#include Timer0.hunsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;void TimeShow(void)//时间显示功能
{DS1302_ReadTime();//读取时间LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒
}void TimeSet(void)//时间设置功能
{if(KeyNum2)//按键2按下{TimeSetSelect;//设置选择位加1TimeSetSelect%6;//越界清零}if(KeyNum3)//按键3按下{DS1302_Time[TimeSetSelect];//时间设置位数值加1if(DS1302_Time[0]99){DS1302_Time[0]0;}//年越界判断if(DS1302_Time[1]12){DS1302_Time[1]1;}//月越界判断if( DS1302_Time[1]1 || DS1302_Time[1]3 || DS1302_Time[1]5 || DS1302_Time[1]7 || DS1302_Time[1]8 || DS1302_Time[1]10 || DS1302_Time[1]12)//日越界判断{if(DS1302_Time[2]31){DS1302_Time[2]1;}//大月}else if(DS1302_Time[1]4 || DS1302_Time[1]6 || DS1302_Time[1]9 || DS1302_Time[1]11){if(DS1302_Time[2]30){DS1302_Time[2]1;}//小月}else if(DS1302_Time[1]2){if(DS1302_Time[0]%40){if(DS1302_Time[2]29){DS1302_Time[2]1;}//闰年2月}else{if(DS1302_Time[2]28){DS1302_Time[2]1;}//平年2月}}if(DS1302_Time[3]23){DS1302_Time[3]0;}//时越界判断if(DS1302_Time[4]59){DS1302_Time[4]0;}//分越界判断if(DS1302_Time[5]59){DS1302_Time[5]0;}//秒越界判断}if(KeyNum4)//按键3按下{DS1302_Time[TimeSetSelect]--;//时间设置位数值减1if(DS1302_Time[0]0){DS1302_Time[0]99;}//年越界判断if(DS1302_Time[1]1){DS1302_Time[1]12;}//月越界判断if( DS1302_Time[1]1 || DS1302_Time[1]3 || DS1302_Time[1]5 || DS1302_Time[1]7 || DS1302_Time[1]8 || DS1302_Time[1]10 || DS1302_Time[1]12)//日越界判断{if(DS1302_Time[2]1){DS1302_Time[2]31;}//大月if(DS1302_Time[2]31){DS1302_Time[2]1;}}else if(DS1302_Time[1]4 || DS1302_Time[1]6 || DS1302_Time[1]9 || DS1302_Time[1]11){if(DS1302_Time[2]1){DS1302_Time[2]30;}//小月if(DS1302_Time[2]30){DS1302_Time[2]1;}}else if(DS1302_Time[1]2){if(DS1302_Time[0]%40){if(DS1302_Time[2]1){DS1302_Time[2]29;}//闰年2月if(DS1302_Time[2]29){DS1302_Time[2]1;}}else{if(DS1302_Time[2]1){DS1302_Time[2]28;}//平年2月if(DS1302_Time[2]28){DS1302_Time[2]1;}}}if(DS1302_Time[3]0){DS1302_Time[3]23;}//时越界判断if(DS1302_Time[4]0){DS1302_Time[4]59;}//分越界判断if(DS1302_Time[5]0){DS1302_Time[5]59;}//秒越界判断}//更新显示根据TimeSetSelect和TimeSetFlashFlag判断可完成闪烁功能if(TimeSetSelect0 TimeSetFlashFlag1){LCD_ShowString(1,1, );}else {LCD_ShowNum(1,1,DS1302_Time[0],2);}if(TimeSetSelect1 TimeSetFlashFlag1){LCD_ShowString(1,4, );}else {LCD_ShowNum(1,4,DS1302_Time[1],2);}if(TimeSetSelect2 TimeSetFlashFlag1){LCD_ShowString(1,7, );}else {LCD_ShowNum(1,7,DS1302_Time[2],2);}if(TimeSetSelect3 TimeSetFlashFlag1){LCD_ShowString(2,1, );}else {LCD_ShowNum(2,1,DS1302_Time[3],2);}if(TimeSetSelect4 TimeSetFlashFlag1){LCD_ShowString(2,4, );}else {LCD_ShowNum(2,4,DS1302_Time[4],2);}if(TimeSetSelect5 TimeSetFlashFlag1){LCD_ShowString(2,7, );}else {LCD_ShowNum(2,7,DS1302_Time[5],2);}
}void main()
{LCD_Init();DS1302_Init();Timer0Init();LCD_ShowString(1,1, - - );//静态字符初始化显示LCD_ShowString(2,1, : : );DS1302_SetTime();//设置时间while(1){KeyNumKey();//读取键码if(KeyNum1)//按键1按下{if(MODE0){MODE1;TimeSetSelect0;}//功能切换else if(MODE1){MODE0;DS1302_SetTime();}}switch(MODE)//根据不同的功能执行不同的函数{case 0:TimeShow();break;case 1:TimeSet();break;}}
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 0x18; //设置定时初值TH0 0xFC; //设置定时初值T0Count;if(T0Count500)//每500ms进入一次{T0Count0;TimeSetFlashFlag!TimeSetFlashFlag;//闪烁标志位取反}
}DS1302.c
#include STC89C5xRC.H//引脚定义
sbit DS1302_SCLKP3^6;
sbit DS1302_IOP3^4;
sbit DS1302_CEP3^5;//寄存器写入地址/指令定义
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E//时间数组索引0~6分别为年、月、日、时、分、秒、星期设置为有符号的便于0的判断
char DS1302_Time[]{19,11,16,12,59,55,6};/*** brief DS1302初始化* param 无* retval 无*/
void DS1302_Init(void)
{DS1302_CE0;DS1302_SCLK0;
}/*** brief DS1302写一个字节* param Command 命令字/地址* param Data 要写入的数据* retval 无*/
void DS1302_WriteByte(unsigned char Command,Data)
{unsigned char i;DS1302_CE1;for(i0;i8;i){DS1302_IOCommand(0x01i);DS1302_SCLK1;DS1302_SCLK0;}for(i0;i8;i){DS1302_IOData(0x01i);DS1302_SCLK1;DS1302_SCLK0;}DS1302_CE0;
}/*** brief DS1302读一个字节* param Command 命令字/地址* retval 读出的数据*/
unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i,Data0x00;Command|0x01; //将指令转换为读指令DS1302_CE1;for(i0;i8;i){DS1302_IOCommand(0x01i);DS1302_SCLK0;DS1302_SCLK1;}for(i0;i8;i){DS1302_SCLK1;DS1302_SCLK0;if(DS1302_IO){Data|(0x01i);}}DS1302_CE0;DS1302_IO0; //读取后将IO设置为0否则读出的数据会出错return Data;
}/*** brief DS1302设置时间调用之后DS1302_Time数组的数字会被设置到DS1302中* param 无* retval 无*/
void DS1302_SetTime(void)
{DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16DS1302_Time[0]%10);//十进制转BCD码后写入DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP,0x80);
}/*** brief DS1302读取时间调用之后DS1302中的数据会被读取到DS1302_Time数组中* param 无* retval 无*/
void DS1302_ReadTime(void)
{unsigned char Temp;TempDS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]Temp/16*10Temp%16;//BCD码转十进制后读取TempDS1302_ReadByte(DS1302_MONTH);DS1302_Time[1]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_DATE);DS1302_Time[2]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_HOUR);DS1302_Time[3]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_MINUTE);DS1302_Time[4]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_SECOND);DS1302_Time[5]Temp/16*10Temp%16;TempDS1302_ReadByte(DS1302_DAY);DS1302_Time[6]Temp/16*10Temp%16;
}DS1302.h
#ifndef __DS1302_H__
#define __DS1302_H__//外部可调用时间数组索引0~6分别为年、月、日、时、分、秒、星期设置为有符号的便于0的判断
extern char DS1302_Time[];void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);#endif2、遇到问题
*** FATAL ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED MODULE: D:\KEIL5\C51\LIB\C51S.LIB (-----) LIMIT: 0800H BYTES Target not created. Build Time Elapsed: 00:00:01 3、解决方式 二十五、单片机实操二十三蜂鸣器与播放提示音
1、蜂鸣器介绍 2、驱动电路 3、ULN2003 4、硬件原理图
无源蜂鸣器使用的控制引脚是P25 5、钢琴键盘与音符对照 6、 简谱 7、C调音符与频率对照表 8、编写程序
main.c
#include STC89C5xRC.H
#include Delay.h
#include Key.h
#include Nixie.h
#include Buzzer.hunsigned char KeyNum;void main()
{Nixie(1,0);while(1){KeyNumKey();if(KeyNum){Buzzer_Time(1000);Nixie(1,KeyNum);}}
}
Buzzer.c
#include STC89C5xRC.H
#include INTRINS.Hsbit BuzzerP2^5;void Buzzer_Delay500us() //11.0592MHz
{unsigned char i;_nop_();i 227;while (--i);
}void Buzzer_Time(unsigned int ms)
{unsigned int i;for(i0;ims*2;i){Buzzer!Buzzer;Buzzer_Delay500us();}
}
Buzzer.h
#ifndef __BUZZER_H__
#define __BUZZER_H__void Buzzer_Time(unsigned int ms);#endif
二十六、单片机实操二十四蜂鸣器与播放提示音
1、音符对应的重载值计算方式 2、编写天空之城音乐程序
main.c
#include STC89C5xRC.H
#include Delay.h
#include Timer0.h//蜂鸣器端口定义
sbit BuzzerP2^5;//播放速度值为四分音符的时长(ms)
#define SPEED 500//音符与索引对应表P休止符L低音M中音H高音下划线升半音符号#
#define P 0
#define L1 1
#define L1_ 2
#define L2 3
#define L2_ 4
#define L3 5
#define L4 6
#define L4_ 7
#define L5 8
#define L5_ 9
#define L6 10
#define L6_ 11
#define L7 12
#define M1 13
#define M1_ 14
#define M2 15
#define M2_ 16
#define M3 17
#define M4 18
#define M4_ 19
#define M5 20
#define M5_ 21
#define M6 22
#define M6_ 23
#define M7 24
#define H1 25
#define H1_ 26
#define H2 27
#define H2_ 28
#define H3 29
#define H4 30
#define H4_ 31
#define H5 32
#define H5_ 33
#define H6 34
#define H6_ 35
#define H7 36//索引与频率对照表
unsigned int FreqTable[]{0,63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,
};//乐谱
unsigned char code Music[]{//音符,时值,//1P, 4,P, 4,P, 4,M6, 2,M7, 2,H1, 42,M7, 2,H1, 4,H3, 4,M7, 444,M3, 2,M3, 2,//2M6, 42,M5, 2,M6, 4,H1, 4,M5, 444,M3, 4,M4, 42,M3, 2,M4, 4,H1, 4,//3M3, 44,P, 2,H1, 2,H1, 2,H1, 2,M7, 42,M4_,2,M4_,4,M7, 4,M7, 8,P, 4,M6, 2,M7, 2,//4H1, 42,M7, 2,H1, 4,H3, 4,M7, 444,M3, 2,M3, 2,M6, 42,M5, 2,M6, 4,H1, 4,//5M5, 444,M2, 2,M3, 2,M4, 4,H1, 2,M7, 22,H1, 24,H2, 2,H2, 2,H3, 2,H1, 244,//6H1, 2,M7, 2,M6, 2,M6, 2,M7, 4,M5_,4,M6, 444,H1, 2,H2, 2,H3, 42,H2, 2,H3, 4,H5, 4,//7H2, 444,M5, 2,M5, 2,H1, 42,M7, 2,H1, 4,H3, 4,H3, 4444,//8M6, 2,M7, 2,H1, 4,M7, 4,H2, 2,H2, 2,H1, 42,M5, 244,H4, 4,H3, 4,H3, 4,H1, 4,//9H3, 444,H3, 4,H6, 44,H5, 4,H5, 4,H3, 2,H2, 2,H1, 44,P, 2,H1, 2,//10H2, 4,H1, 2,H2, 2,H2, 4,H5, 4,H3, 444,H3, 4,H6, 44,H5, 44,//11H3, 2,H2, 2,H1, 44,P, 2,H1, 2,H2, 4,H1, 2,H2, 24,M7, 4,M6, 444,P, 4,0xFF //终止标志
};unsigned char FreqSelect,MusicSelect;void main()
{Timer0Init();while(1){if(Music[MusicSelect]!0xFF) //如果不是停止标志位{FreqSelectMusic[MusicSelect]; //选择音符对应的频率MusicSelect;Delay(SPEED/4*Music[MusicSelect]); //选择音符对应的时值MusicSelect;TR00;Delay(5); //音符间短暂停顿TR01;}else //如果是停止标志位{TR00;while(1);}}
}void Timer0_Routine() interrupt 1
{if(FreqTable[FreqSelect]) //如果不是休止符{/*取对应频率值的重装载值到定时器*/TL0 FreqTable[FreqSelect]%256; //设置定时初值TH0 FreqTable[FreqSelect]/256; //设置定时初值Buzzer!Buzzer; //翻转蜂鸣器IO口}
}二十七、单片机实操二十五AT24C02I2C总线与数据存储
1、存储器介绍 2、存储器简化模型 3、AT24C02介绍 4、引脚与芯片电路 5、内部结构框图 6、I2C总线介绍 7、I2C电路规范 8、I2C时序结构 9、I2C数据帧 10、AT24C02数据帧 11、编写程序
main.c
#include STC89C5xRC.H#include LCD1602.h
#include Key.h
#include AT24C02.h
#include Delay.hunsigned char KeyNum;
unsigned int Num;void main()
{LCD_Init();LCD_ShowNum(1,1,Num,5);while(1){KeyNumKey();if(KeyNum1) //K1按键Num自增{Num;LCD_ShowNum(1,1,Num,5);}if(KeyNum2) //K2按键Num自减{Num--;LCD_ShowNum(1,1,Num,5);}if(KeyNum3) //K3按键向AT24C02写入数据{AT24C02_WriteByte(0,Num%256);Delay(5);AT24C02_WriteByte(1,Num/256);Delay(5);LCD_ShowString(2,1,Write OK);Delay(1000);LCD_ShowString(2,1, );}if(KeyNum4) //K4按键从AT24C02读取数据{NumAT24C02_ReadByte(0);Num|AT24C02_ReadByte(1)8;LCD_ShowNum(1,1,Num,5);LCD_ShowString(2,1,Read OK );Delay(1000);LCD_ShowString(2,1, );}}
}I2C.c
#include STC89C5xRC.Hsbit I2C_SCLP2^1;
sbit I2C_SDAP2^0;/*** brief I2C开始* param 无* retval 无*/
void I2C_Start(void)
{I2C_SDA1;I2C_SCL1;I2C_SDA0;I2C_SCL0;
}/*** brief I2C停止* param 无* retval 无*/
void I2C_Stop(void)
{I2C_SDA0;I2C_SCL1;I2C_SDA1;
}/*** brief I2C发送一个字节* param Byte 要发送的字节* retval 无*/
void I2C_SendByte(unsigned char Byte)
{unsigned char i;for(i0;i8;i){I2C_SDAByte(0x80i);I2C_SCL1;I2C_SCL0;}
}/*** brief I2C接收一个字节* param 无* retval 接收到的一个字节数据*/
unsigned char I2C_ReceiveByte(void)
{unsigned char i,Byte0x00;I2C_SDA1;for(i0;i8;i){I2C_SCL1;if(I2C_SDA){Byte|(0x80i);}I2C_SCL0;}return Byte;
}/*** brief I2C发送应答* param AckBit 应答位0为应答1为非应答* retval 无*/
void I2C_SendAck(unsigned char AckBit)
{I2C_SDAAckBit;I2C_SCL1;I2C_SCL0;
}/*** brief I2C接收应答位* param 无* retval 接收到的应答位0为应答1为非应答*/
unsigned char I2C_ReceiveAck(void)
{unsigned char AckBit;I2C_SDA1;I2C_SCL1;AckBitI2C_SDA;I2C_SCL0;return AckBit;
}I2C.h
#ifndef __I2C_H__
#define __I2C_H__void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);#endifAT21C02.c
#include STC89C5xRC.H#include I2C.h#define AT24C02_ADDRESS 0xA0/*** brief AT24C02写入一个字节* param WordAddress 要写入字节的地址* param Data 要写入的数据* retval 无*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();
}/*** brief AT24C02读取一个字节* param WordAddress 要读出字节的地址* retval 读出的数据*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C02_ADDRESS|0x01);I2C_ReceiveAck();DataI2C_ReceiveByte();I2C_SendAck(1);I2C_Stop();return Data;
}AT21C02.h
#ifndef __AT24C02_H__
#define __AT24C02_H__void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);#endif二十八、单片机实操二十六秒表(定时器扫描按键数码管)
1、编写程序
main.c
#include STC89C5xRC.H
#include Timer0.h
#include Key.h
#include Nixie.h
#include Delay.h
#include AT24C02.hunsigned char KeyNum;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;void main()
{Timer0_Init();while(1){KeyNumKey();if(KeyNum1) //K1按键按下{RunFlag!RunFlag; //启动标志位翻转}if(KeyNum2) //K2按键按下{Min0; //分秒清0Sec0;MiniSec0;}if(KeyNum3) //K3按键按下{AT24C02_WriteByte(0,Min); //将分秒写入AT24C02Delay(5);AT24C02_WriteByte(1,Sec);Delay(5);AT24C02_WriteByte(2,MiniSec);Delay(5);}if(KeyNum4) //K4按键按下{MinAT24C02_ReadByte(0); //读出AT24C02数据SecAT24C02_ReadByte(1);MiniSecAT24C02_ReadByte(2);}Nixie_SetBuf(1,Min/10); //设置显示缓存显示数据Nixie_SetBuf(2,Min%10);Nixie_SetBuf(3,11);Nixie_SetBuf(4,Sec/10);Nixie_SetBuf(5,Sec%10);Nixie_SetBuf(6,11);Nixie_SetBuf(7,MiniSec/10);Nixie_SetBuf(8,MiniSec%10);}
}/*** brief 秒表驱动函数在中断中调用* param 无* retval 无*/
void Sec_Loop(void)
{if(RunFlag){MiniSec;if(MiniSec100){MiniSec0;Sec;if(Sec60){Sec0;Min;if(Min60){Min0;}}}}
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count1,T0Count2,T0Count3;TL0 0x18; //设置定时初值TH0 0xFC; //设置定时初值T0Count1;if(T0Count120){T0Count10;Key_Loop(); //20ms调用一次按键驱动函数}T0Count2;if(T0Count22){T0Count20;Nixie_Loop();//2ms调用一次数码管驱动函数}T0Count3;if(T0Count310){T0Count30;Sec_Loop(); //10ms调用一次数秒表驱动函数}
}Key.c
#include STC89C5xRC.H
#include Delay.hunsigned char Key_KeyNumber;/*** brief 获取按键键码* param 无* retval 按下按键的键码范围0,1~4,0表示无按键按下*/
unsigned char Key(void)
{unsigned char Temp0;TempKey_KeyNumber;Key_KeyNumber0;return Temp;
}/*** brief 获取当前按键的状态无消抖及松手检测* param 无* retval 按下按键的键码范围0,1~4,0表示无按键按下*/
unsigned char Key_GetState()
{unsigned char KeyNumber0;if(P310){KeyNumber1;}if(P300){KeyNumber2;}if(P320){KeyNumber3;}if(P330){KeyNumber4;}return KeyNumber;
}/*** brief 按键驱动函数在中断中调用* param 无* retval 无*/
void Key_Loop(void)
{static unsigned char NowState,LastState;LastStateNowState; //按键状态更新NowStateKey_GetState(); //获取当前按键状态//如果上个时间点按键按下这个时间点未按下则是松手瞬间以此避免消抖和松手检测if(LastState1 NowState0){Key_KeyNumber1;}if(LastState2 NowState0){Key_KeyNumber2;}if(LastState3 NowState0){Key_KeyNumber3;}if(LastState4 NowState0){Key_KeyNumber4;}
}Key.h
#ifndef __KEY_H__
#define __KEY_H__unsigned char Key(void);
void Key_Loop(void);#endifNixie.c
#include STC89C5xRC.H
#include Delay.h//数码管显示缓存区
unsigned char Nixie_Buf[9]{0,10,10,10,10,10,10,10,10};//数码管段码表
unsigned char NixieTable[]{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};/*** brief 设置显示缓存区* param Location 要设置的位置范围1~8* param Number 要设置的数字范围段码表索引范围* retval 无*/
void Nixie_SetBuf(unsigned char Location,Number)
{Nixie_Buf[Location]Number;
}/*** brief 数码管扫描显示* param Location 要显示的位置范围1~8* param Number 要显示的数字范围段码表索引范围* retval 无*/
void Nixie_Scan(unsigned char Location,Number)
{P00x00; //段码清0消影switch(Location) //位码输出{case 1:P241;P231;P221;break;case 2:P241;P231;P220;break;case 3:P241;P230;P221;break;case 4:P241;P230;P220;break;case 5:P240;P231;P221;break;case 6:P240;P231;P220;break;case 7:P240;P230;P221;break;case 8:P240;P230;P220;break;}P0NixieTable[Number]; //段码输出
}/*** brief 数码管驱动函数在中断中调用* param 无* retval 无*/
void Nixie_Loop(void)
{static unsigned char i1;Nixie_Scan(i,Nixie_Buf[i]);i;if(i9){i1;}
}Nixie.h
#ifndef __NIXIE_H__
#define __NIXIE_H__void Nixie_SetBuf(unsigned char Location,Number);
void Nixie_Scan(unsigned char Location,Number);
void Nixie_Loop(void);#endif二十九、单片机实操二十七DS18B20温度传感器与温度读取
1、DS18B20介绍 2、 引脚及应用电路 3、内部结构图 4、存储器结构 5、单总线介绍 6、单总线电路规范 7、单总线时序结构 8、DS18B20操作流程 9、DS18B20数据帧 10、温度存储格式 11、编写程序
main.c
#include STC89C5xRC.H
#include LCD1602.h
#include DS18B20.h
#include Delay.h
#include AT24C02.h
#include Key.h
#include Timer0.hfloat T,TShow;
char TLow,THigh;
unsigned char KeyNum;void main()
{DS18B20_ConvertT(); //上电先转换一次温度防止第一次读数据错误Delay(1000); //等待转换完成THighAT24C02_ReadByte(0); //读取温度阈值数据TLowAT24C02_ReadByte(1);if(THigh125 || TLow-55 || THighTLow){THigh20; //如果阈值非法则设为默认值TLow15;}LCD_Init();LCD_ShowString(1,1,T:);LCD_ShowString(2,1,TH:);LCD_ShowString(2,9,TL:);LCD_ShowSignedNum(2,4,THigh,3);LCD_ShowSignedNum(2,12,TLow,3);Timer0_Init();while(1){KeyNumKey();/*温度读取及显示*/DS18B20_ConvertT(); //转换温度TDS18B20_ReadT(); //读取温度if(T0) //如果温度小于0{LCD_ShowChar(1,3,-); //显示负号TShow-T; //将温度变为正数}else //如果温度大于等于0{LCD_ShowChar(1,3,); //显示正号TShowT;}LCD_ShowNum(1,4,TShow,3); //显示温度整数部分LCD_ShowChar(1,7,.); //显示小数点LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分/*阈值判断及显示*/if(KeyNum){if(KeyNum1) //K1按键THigh自增{THigh;if(THigh125){THigh125;}}if(KeyNum2) //K2按键THigh自减{THigh--;if(THighTLow){THigh;}}if(KeyNum3) //K3按键TLow自增{TLow;if(TLowTHigh){TLow--;}}if(KeyNum4) //K4按键TLow自减{TLow--;if(TLow-55){TLow-55;}}LCD_ShowSignedNum(2,4,THigh,3); //显示阈值数据LCD_ShowSignedNum(2,12,TLow,3);AT24C02_WriteByte(0,THigh); //写入到At24C02中保存Delay(5);AT24C02_WriteByte(1,TLow);Delay(5);}if(TTHigh) //越界判断{LCD_ShowString(1,13,OV:H);}else if(TTLow){LCD_ShowString(1,13,OV:L);}else{LCD_ShowString(1,13, );}}
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 0x18; //设置定时初值TH0 0xFC; //设置定时初值T0Count;if(T0Count20){T0Count0;Key_Loop(); //每20ms调用一次按键驱动函数}
}OneWrite.c
#include STC89C5xRC.H
//引脚定义
sbit OneWire_DQP3^7;/*** brief 单总线初始化* param 无* retval 从机响应位0为响应1为未响应*/
unsigned char OneWire_Init(void)
{unsigned char i;unsigned char AckBit;OneWire_DQ1;OneWire_DQ0;i 247;while (--i); //Delay 500usOneWire_DQ1;i 32;while (--i); //Delay 70usAckBitOneWire_DQ;i 247;while (--i); //Delay 500usreturn AckBit;
}/*** brief 单总线发送一位* param Bit 要发送的位* retval 无*/
void OneWire_SendBit(unsigned char Bit)
{unsigned char i;OneWire_DQ0;i 4;while (--i); //Delay 10usOneWire_DQBit;i 24;while (--i); //Delay 50usOneWire_DQ1;
}/*** brief 单总线接收一位* param 无* retval 读取的位*/
unsigned char OneWire_ReceiveBit(void)
{unsigned char i;unsigned char Bit;OneWire_DQ0;i 2;while (--i); //Delay 5usOneWire_DQ1;i 2;while (--i); //Delay 5usBitOneWire_DQ;i 24;while (--i); //Delay 50usreturn Bit;
}/*** brief 单总线发送一个字节* param Byte 要发送的字节* retval 无*/
void OneWire_SendByte(unsigned char Byte)
{unsigned char i;for(i0;i8;i){OneWire_SendBit(Byte(0x01i));}
}/*** brief 单总线接收一个字节* param 无* retval 接收的一个字节*/
unsigned char OneWire_ReceiveByte(void)
{unsigned char i;unsigned char Byte0x00;for(i0;i8;i){if(OneWire_ReceiveBit()){Byte|(0x01i);}}return Byte;
}OneWrite.h
#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__unsigned char OneWire_Init(void);
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit(void);
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte(void);#endif三十、单片机实操二十八温度报警器
1、编写代码
main.c
#include STC89C5xRC.H
#include LCD1602.h
#include DS18B20.h
#include Delay.h
#include AT24C02.h
#include Key.h
#include Timer0.hfloat T,TShow;
char TLow,THigh;
unsigned char KeyNum;void main()
{DS18B20_ConvertT(); //上电先转换一次温度防止第一次读数据错误Delay(1000); //等待转换完成THighAT24C02_ReadByte(0); //读取温度阈值数据TLowAT24C02_ReadByte(1);if(THigh125 || TLow-55 || THighTLow){THigh20; //如果阈值非法则设为默认值TLow15;}LCD_Init();LCD_ShowString(1,1,T:);LCD_ShowString(2,1,TH:);LCD_ShowString(2,9,TL:);LCD_ShowSignedNum(2,4,THigh,3);LCD_ShowSignedNum(2,12,TLow,3);Timer0_Init();while(1){KeyNumKey();/*温度读取及显示*/DS18B20_ConvertT(); //转换温度TDS18B20_ReadT(); //读取温度if(T0) //如果温度小于0{LCD_ShowChar(1,3,-); //显示负号TShow-T; //将温度变为正数}else //如果温度大于等于0{LCD_ShowChar(1,3,); //显示正号TShowT;}LCD_ShowNum(1,4,TShow,3); //显示温度整数部分LCD_ShowChar(1,7,.); //显示小数点LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分/*阈值判断及显示*/if(KeyNum){if(KeyNum1) //K1按键THigh自增{THigh;if(THigh125){THigh125;}}if(KeyNum2) //K2按键THigh自减{THigh--;if(THighTLow){THigh;}}if(KeyNum3) //K3按键TLow自增{TLow;if(TLowTHigh){TLow--;}}if(KeyNum4) //K4按键TLow自减{TLow--;if(TLow-55){TLow-55;}}LCD_ShowSignedNum(2,4,THigh,3); //显示阈值数据LCD_ShowSignedNum(2,12,TLow,3);AT24C02_WriteByte(0,THigh); //写入到At24C02中保存Delay(5);AT24C02_WriteByte(1,TLow);Delay(5);}if(TTHigh) //越界判断{LCD_ShowString(1,13,OV:H);}else if(TTLow){LCD_ShowString(1,13,OV:L);}else{LCD_ShowString(1,13, );}}
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 0x18; //设置定时初值TH0 0xFC; //设置定时初值T0Count;if(T0Count20){T0Count0;Key_Loop(); //每20ms调用一次按键驱动函数}
}三十一、单片机实操二十九LCD1602与功能函数代码
1、LCD1602介绍 2、引脚及应用电路 3、内部结构框图 4、存储器结构 5、时序结构 6、LS1602指令集 7、LCD1602操作流程 8、编写代码
详见LCD1602模块。
三十二、单片机实操三十直流电机驱动PWM与LED呼吸灯
1、直流电机介绍 2、电机驱动电路 3、PWM介绍 4、产生PWM的方法 5、编写程序
main.c
#include STC89C5xRC.Hsbit LEDP2^0;void Delay(unsigned int t)
{while(t--);
}void main()
{unsigned char Time,i;while(1){for(Time0;Time100;Time) //改变亮灭时间由暗到亮{for(i0;i20;i) //计次延时{LED0; //LED亮Delay(Time); //延时TimeLED1; //LED灭Delay(100-Time); //延时100-Time}}for(Time100;Time0;Time--) //改变亮灭时间由亮到暗{for(i0;i20;i) //计次延时{LED0; //LED亮Delay(Time); //延时TimeLED1; //LED灭Delay(100-Time); //延时100-Time}}}
}三十三、单片机实操三十一直流电机调速
1、编写程序
main.c
#include STC89C5xRC.H#include Delay.h
#include Key.h
#include Nixie.h
#include Timer0.hsbit MotorP1^0;unsigned char Counter,Compare; //计数值和比较值用于输出PWM
unsigned char KeyNum,Speed;void main()
{Timer0_Init();while(1){KeyNumKey();if(KeyNum1){Speed;Speed%4;if(Speed0){Compare0;} //设置比较值改变PWM占空比if(Speed1){Compare50;}if(Speed2){Compare75;}if(Speed3){Compare100;}}Nixie(1,Speed);}
}void Timer0_Routine() interrupt 1
{TL0 0x9C; //设置定时初值TH0 0xFF; //设置定时初值Counter;Counter%100; //计数值变化范围限制在0~99if(CounterCompare) //计数值小于比较值{Motor1; //输出1}else //计数值大于比较值{Motor0; //输出0}
}三十四、单片机实操三十二AD/DA之AD模数转换
1、AD/DA介绍 2、硬件电路模型 3、硬件电路 4、运算放大器 5、运放电路 6、DA原理 7、AD原理 8、AD/DA性能指标 9、XPT2046功能说明 10、 XPT2046时序 11、开发板原理图 8、编写代码
main.c #include STC89C5xRC.H
#include Delay.h
#include LCD1602.h
#include XPT2046.hunsigned int ADValue;void main(void)
{LCD_Init();LCD_ShowString(1,1,ADJ NTC GR);while(1){ADValueXPT2046_ReadAD(XPT2046_XP); //读取AIN0可调电阻LCD_ShowNum(2,1,ADValue,3); //显示AIN0ADValueXPT2046_ReadAD(XPT2046_YP); //读取AIN1热敏电阻LCD_ShowNum(2,6,ADValue,3); //显示AIN1ADValueXPT2046_ReadAD(XPT2046_VBAT); //读取AIN2光敏电阻LCD_ShowNum(2,11,ADValue,3); //显示AIN2Delay(100);}
}XPT2046.c
#include STC89C5xRC.H#include INTRINS.H//引脚定义
sbit XPY2046_DINP3^4;
sbit XPY2046_CSP3^5;
sbit XPY2046_DCLKP3^6;
sbit XPY2046_DOUTP3^7;/*** brief ZPT2046读取AD值* param Command 命令字范围头文件内定义的宏结尾的数字表示转换的位数* retval AD转换后的数字量范围8位为0~25512位为0~4095*/
unsigned int XPT2046_ReadAD(unsigned char Command)
{unsigned char i;unsigned int Data0;XPY2046_DCLK0;XPY2046_CS0;for(i0;i8;i){XPY2046_DINCommand(0x80i);XPY2046_DCLK1;XPY2046_DCLK0;}for(i0;i16;i){XPY2046_DCLK1;XPY2046_DCLK0;if(XPY2046_DOUT){Data|(0x8000i);}}XPY2046_CS1;return Data8;
}XPT2046.h
#ifndef __XPT2046_H__
#define __XPT2046_H__#define XPT2046_VBAT 0xAC
#define XPT2046_AUX 0xEC
#define XPT2046_XP 0x9C //0xBC
#define XPT2046_YP 0xDCunsigned int XPT2046_ReadAD(unsigned char Command);#endif三十五、单片机实操三十三DA数模转换
1、编写代码
main.c
#include STC89C5xRC.H#include Delay.h
#include Timer0.hsbit DAP2^1;unsigned char Counter,Compare; //计数值和比较值用于输出PWM
unsigned char i;void main()
{Timer0_Init();while(1){for(i0;i100;i){Comparei; //设置比较值改变PWM占空比Delay(10);}for(i100;i0;i--){Comparei; //设置比较值改变PWM占空比Delay(10);}}
}void Timer0_Routine() interrupt 1
{TL0 0x9C; //设置定时初值TH0 0xFF; //设置定时初值Counter;Counter%100; //计数值变化范围限制在0~99if(CounterCompare) //计数值小于比较值{DA1; //输出1}else //计数值大于比较值{DA0; //输出0}
}三十六、单片机实操三十四红外遥控与外部中断
1、红外遥控简介 2、 硬件电路 3、基本发送与接收 4、NEC编码 5、 遥控器键码 6、51单片机的外部中断 7、外部中断寄存器 8、编写程序
main.c
#include STC89C5xRC.H#include Delay.h
#include LCD1602.h
#include IR.hunsigned char Num;
unsigned char Address;
unsigned char Command;void main()
{LCD_Init();LCD_ShowString(1,1,ADDR CMD NUM);LCD_ShowString(2,1,00 00 000);IR_Init();while(1){if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧{AddressIR_GetAddress(); //获取遥控器地址码CommandIR_GetCommand(); //获取遥控器命令码LCD_ShowHexNum(2,1,Address,2); //显示遥控器地址码LCD_ShowHexNum(2,7,Command,2); //显示遥控器命令码if(CommandIR_VOL_MINUS) //如果遥控器VOL-按键按下{Num--; //Num自减}if(CommandIR_VOL_ADD) //如果遥控器VOL按键按下{Num; //Num自增}LCD_ShowNum(2,12,Num,3); //显示Num}}
}
IR.c
#include STC89C5xRC.H#include Timer0.h
#include Int0.hunsigned int IR_Time;
unsigned char IR_State;unsigned char IR_Data[4];
unsigned char IR_pData;unsigned char IR_DataFlag;
unsigned char IR_RepeatFlag;
unsigned char IR_Address;
unsigned char IR_Command;/*** brief 红外遥控初始化* param 无* retval 无*/
void IR_Init(void)
{Timer0_Init();Int0_Init();
}/*** brief 红外遥控获取收到数据帧标志位* param 无* retval 是否收到数据帧1为收到0为未收到*/
unsigned char IR_GetDataFlag(void)
{if(IR_DataFlag){IR_DataFlag0;return 1;}return 0;
}/*** brief 红外遥控获取收到连发帧标志位* param 无* retval 是否收到连发帧1为收到0为未收到*/
unsigned char IR_GetRepeatFlag(void)
{if(IR_RepeatFlag){IR_RepeatFlag0;return 1;}return 0;
}/*** brief 红外遥控获取收到的地址数据* param 无* retval 收到的地址数据*/
unsigned char IR_GetAddress(void)
{return IR_Address;
}/*** brief 红外遥控获取收到的命令数据* param 无* retval 收到的命令数据*/
unsigned char IR_GetCommand(void)
{return IR_Command;
}//外部中断0中断函数下降沿触发执行
void Int0_Routine(void) interrupt 0
{if(IR_State0) //状态0空闲状态{Timer0_SetCounter(0); //定时计数器清0Timer0_Run(1); //定时器启动IR_State1; //置状态为1}else if(IR_State1) //状态1等待Start信号或Repeat信号{IR_TimeTimer0_GetCounter(); //获取上一次中断到此次中断的时间Timer0_SetCounter(0); //定时计数器清0//如果计时为13.5ms则接收到了Start信号判定值在12MHz晶振下为13500在11.0592MHz晶振下为12442if(IR_Time12442-500 IR_Time12442500){IR_State2; //置状态为2}//如果计时为11.25ms则接收到了Repeat信号判定值在12MHz晶振下为11250在11.0592MHz晶振下为10368else if(IR_Time10368-500 IR_Time10368500){IR_RepeatFlag1; //置收到连发帧标志位为1Timer0_Run(0); //定时器停止IR_State0; //置状态为0}else //接收出错{IR_State1; //置状态为1}}else if(IR_State2) //状态2接收数据{IR_TimeTimer0_GetCounter(); //获取上一次中断到此次中断的时间Timer0_SetCounter(0); //定时计数器清0//如果计时为1120us则接收到了数据0判定值在12MHz晶振下为1120在11.0592MHz晶振下为1032if(IR_Time1032-500 IR_Time1032500){IR_Data[IR_pData/8]~(0x01(IR_pData%8)); //数据对应位清0IR_pData; //数据位置指针自增}//如果计时为2250us则接收到了数据1判定值在12MHz晶振下为2250在11.0592MHz晶振下为2074else if(IR_Time2074-500 IR_Time2074500){IR_Data[IR_pData/8]|(0x01(IR_pData%8)); //数据对应位置1IR_pData; //数据位置指针自增}else //接收出错{IR_pData0; //数据位置指针清0IR_State1; //置状态为1}if(IR_pData32) //如果接收到了32位数据{IR_pData0; //数据位置指针清0if((IR_Data[0]~IR_Data[1]) (IR_Data[2]~IR_Data[3])) //数据验证{IR_AddressIR_Data[0]; //转存数据IR_CommandIR_Data[2];IR_DataFlag1; //置收到连发帧标志位为1}Timer0_Run(0); //定时器停止IR_State0; //置状态为0}}
}IR.h
#ifndef __IR_H__
#define __IR_H__#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4Avoid IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);#endifInt0.c
#include STC89C5xRC.H/*** brief 外部中断0初始化* param 无* retval 无*/
void Int0_Init(void)
{IT01;IE00;EX01;EA1;PX01;
}/*外部中断0中断函数模板
void Int0_Routine(void) interrupt 0
{}
*/Int0.h
#ifndef __INT0_H__
#define __INT0_H__void Int0_Init(void);#endifTimer0.c
#include STC89C5xRC.H/*** brief 定时器0初始化* param 无* retval 无*/
void Timer0_Init(void)
{TMOD 0xF0; //设置定时器模式TMOD | 0x01; //设置定时器模式TL0 0; //设置定时初值TH0 0; //设置定时初值TF0 0; //清除TF0标志TR0 0; //定时器0不计时
}/*** brief 定时器0设置计数器值* param Value要设置的计数器值范围0~65535* retval 无*/
void Timer0_SetCounter(unsigned int Value)
{TH0Value/256;TL0Value%256;
}/*** brief 定时器0获取计数器值* param 无* retval 计数器值范围0~65535*/
unsigned int Timer0_GetCounter(void)
{return (TH08)|TL0;
}/*** brief 定时器0启动停止控制* param Flag 启动停止标志1为启动0为停止* retval 无*/
void Timer0_Run(unsigned char Flag)
{TR0Flag;
}Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0_Init(void);
void Timer0_SetCounter(unsigned int Value);
unsigned int Timer0_GetCounter(void);
void Timer0_Run(unsigned char Flag);#endif三十七、单片机实操三十五红外遥控电机调速
1、编写程序
main.c
#include STC89C5xRC.H#include Delay.h
#include Key.h
#include Nixie.h
#include Motor.h
#include IR.hunsigned char Command,Speed;void main()
{Motor_Init();IR_Init();while(1){if(IR_GetDataFlag()) //如果收到数据帧{CommandIR_GetCommand(); //获取遥控器命令码if(CommandIR_0){Speed0;} //根据遥控器命令码设置速度if(CommandIR_1){Speed1;}if(CommandIR_2){Speed2;}if(CommandIR_3){Speed3;}if(Speed0){Motor_SetSpeed(0);} //速度输出if(Speed1){Motor_SetSpeed(50);}if(Speed2){Motor_SetSpeed(75);}if(Speed3){Motor_SetSpeed(100);}}Nixie(1,Speed); //数码管显示速度}
}
Time1.c
#include STC89C5xRC.H/*** brief 定时器1初始化100us12.000MHz* param 无* retval 无*/
void Timer1_Init(void)
{TMOD 0x0F; //设置定时器模式TMOD | 0x10; //设置定时器模式TL1 0x9C; //设置定时初值TH1 0xFF; //设置定时初值TF1 0; //清除TF1标志TR1 1; //定时器1开始计时ET11;EA1;PT10;
}/*定时器中断函数模板
void Timer1_Routine() interrupt 3
{static unsigned int T1Count;TL1 0x9C; //设置定时初值TH1 0xFF; //设置定时初值T1Count;if(T1Count1000){T1Count0;}
}
*/Time1.h
#ifndef __TIMER1_H__
#define __TIMER1_H__void Timer1_Init(void);#endifMotor.c
#include STC89C5xRC.H#include Timer1.h//引脚定义
sbit MotorP1^0;unsigned char Counter,Compare;/*** brief 电机初始化* param 无* retval 无*/
void Motor_Init(void)
{Timer1_Init();
}/*** brief 电机设置速度* param Speed 要设置的速度范围0~100* retval 无*/
void Motor_SetSpeed(unsigned char Speed)
{CompareSpeed;
}//定时器1中断函数
void Timer1_Routine() interrupt 3
{TL1 0x9C; //设置定时初值TH1 0xFF; //设置定时初值Counter;Counter%100; //计数值变化范围限制在0~99if(CounterCompare) //计数值小于比较值{Motor1; //输出1}else //计数值大于比较值{Motor0; //输出0}
}Motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__void Motor_Init(void);
void Motor_SetSpeed(unsigned char Speed);#endif