赞
踩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
keil本地基础配置:字体,颜色,中文显示:http://t.csdn.cn/coYWL
【1】首先新建工程选择芯片
问题:关于KEIL5最新版没有ATMEL(含89C51芯片)的情况
参考链接:http://t.csdn.cn/1T7Gf
【2】新建文件
【3】设置生产HEX文件后,编译
【4】下载程序到单片机
然后按单片机的总开关,下载成功
提示:以下是本篇文章正文内容,下面案例可供参考
#include <REGX52.H>
void main()
{
P2=0xFE; //1111 1110
while(1)
{
}
}
#include <REGX52.H> #include <INTRINS.H> //自动生成的延时函数 void 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) { P2=0xFE; //1111 1110 Delay500ms(); P2=0xFF; //1111 1111 Delay500ms(); } }
#include <REGX52.H>21 #include <INTRINS.H>//_nop_()的头文件 void Delay500ms() //@12.000MHz { unsigned char i, j, k; _nop_();//1ms左右 i = 4; j = 205; k = 187; do { do { while (--k); } while (--j); } while (--i); } void main() { while(1) { P2=0xFE;//1111 1110 Delay500ms(); P2=0xFD;//1111 1101 Delay500ms(); P2=0xFB;//1111 1011 Delay500ms(); P2=0xF7;//1111 0111 Delay500ms(); P2=0xEF;//1110 1111 Delay500ms(); P2=0xDF;//1101 1111 Delay500ms(); P2=0xBF;//1011 1111 Delay500ms(); P2=0x7F;//0111 1111 Delay500ms(); } }
升级版
#include <REGX52.H> void Delay1ms(unsigned int xms); //@12.000MHz void main() { while(1) { P2=0xFE;//1111 1110 Delay1ms(1000); P2=0xFD;//1111 1101 Delay1ms(1000); P2=0xFB;//1111 1011 Delay1ms(100); P2=0xF7;//1111 0111 Delay1ms(100); P2=0xEF;//1110 1111 Delay1ms(100); P2=0xDF;//1101 1111 Delay1ms(100); P2=0xBF;//1011 1111 Delay1ms(100); P2=0x7F;//0111 1111 Delay1ms(100); } } void Delay1ms(unsigned int xms) //@12.000MHz { unsigned char i, j; while(xms) {//1ms的定时器 i = 2; j = 239; do { while (--j); } while (--i); xms--; } }
按下按键LED灯亮,松开按键LED灯灭
#include <REGX52.H> void main() { while(1) { if(P3_1==0 || P3_0==0) //如果K1按键或K2按键按下 { P2_0=0; //LED1输出0,点亮 } else { P2_0=1; //LED1输出1,熄灭 } } }
按键的抖动
对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动
按下按键没反应,松开按键LED灯亮
#include <REGX52.H> void Delay(unsigned int xms) { unsigned char i, j; while(xms) { i = 2; j = 239; do { while (--j); } while (--i); xms--; } } void main() { while(1) { if(P3_1==0) //如果K1按键按下 { Delay(20); //延时消抖 while(P3_1==0); //松手检测 Delay(20); //延时消抖 P2_0=0; //LED1取反 } } }
按下按键没反应,松开按键LED灯亮,然后再按下按键LED灯没反应,松开按键LED灯灭,以此循环
#include <REGX52.H> void Delay(unsigned int xms) { unsigned char i, j; while(xms) { i = 2; j = 239; do { while (--j); } while (--i); xms--; } } void main() { while(1) { if(P3_1==0) //如果K1按键按下 { Delay(20); //延时消抖 while(P3_1==0); //松手检测 Delay(20); //延时消抖 P2_0=~P2_0; //LED1取反 } } }
注意:P口后面可以是数字,P口是低电平
【1】按下按键,LED1和LED3亮
#include <REGX52.H> void Delay(unsigned int xms) { unsigned char i, j; while(xms--) { i = 2; j = 239; do { while (--j); } while (--i); } } void main() { unsigned char LEDNum=5;//0101 while(1) { if(P3_1==0) //如果K1按键按下 { Delay(20); //延时消抖 while(P3_1==0); //松手检测 Delay(20); //延时消抖 //LEDNum++; //变量自增 P2=~LEDNum; //变量取反输出给LED } } }
【2】独立按键控制LED显示二进制
#include <REGX52.H> void Delay(unsigned int xms) { unsigned char i, j; while(xms--) { i = 2; j = 239; do { while (--j); } while (--i); } } void main() { unsigned char LEDNum=0; while(1) { if(P3_1==0) //如果K1按键按下 { Delay(20); //延时消抖 while(P3_1==0); //松手检测 Delay(20); //延时消抖 LEDNum++; //变量自增 P2=~LEDNum; //变量取反输出给LED } } }
如果K1按键按下,右移;如果K2按键按下,左移;
#include <REGX52.H> void Delay(unsigned int xms); unsigned char LEDNum; void main() { P2=~0x01; //上电默认LED1点亮 while(1) { if(P3_1==0) //如果K1按键按下 { Delay(20); while(P3_1==0); Delay(20); LEDNum++; //LEDNum自增 if(LEDNum>=8) //限制LEDNum自增范围 LEDNum=0; P2=~(0x01<<LEDNum); //LED的第LEDNum位点亮 } if(P3_0==0) //如果K2按键按下 { Delay(20); while(P3_0==0); Delay(20); if(LEDNum==0) //LEDNum减到0后变为7 LEDNum=7; else //LEDNum未减到0,自减 LEDNum--; P2=~(0x01<<LEDNum); //LED的第LEDNum位点亮 } } } void Delay(unsigned int xms) { unsigned char i, j; while(xms--) { i = 2; j = 239; do { while (--j); } while (--i); } }
#include <REGX52.H> //数码管段码表 unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数码管显示子函数 void Nixie(unsigned char Location,Number) { switch(Location) //位码输出 { case 1:P2_4=1;P2_3=1;P2_2=1;break; case 2:P2_4=1;P2_3=1;P2_2=0;break; case 3:P2_4=1;P2_3=0;P2_2=1;break; case 4:P2_4=1;P2_3=0;P2_2=0;break; case 5:P2_4=0;P2_3=1;P2_2=1;break; case 6:P2_4=0;P2_3=1;P2_2=0;break; case 7:P2_4=0;P2_3=0;P2_2=1;break; case 8:P2_4=0;P2_3=0;P2_2=0;break; } P0=NixieTable[Number]; //段码输出 } void main() { Nixie(2,3); //在数码管的第2位置显示3 while(1)//一直执行这行代码,代表数码管常亮 { } }
#include <REGX52.H> //数码管段码表 unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //延时子函数 void Delay(unsigned int xms) { unsigned char i, j; while(xms--) { i = 2; j = 239; do { while (--j); } while (--i); } } //数码管显示子函数 void Nixie(unsigned char Location,Number) { switch(Location) //位码输出 { case 1:P2_4=1;P2_3=1;P2_2=1;break; case 2:P2_4=1;P2_3=1;P2_2=0;break; case 3:P2_4=1;P2_3=0;P2_2=1;break; case 4:P2_4=1;P2_3=0;P2_2=0;break; case 5:P2_4=0;P2_3=1;P2_2=1;break; case 6:P2_4=0;P2_3=1;P2_2=0;break; case 7:P2_4=0;P2_3=0;P2_2=1;break; case 8:P2_4=0;P2_3=0;P2_2=0;break; } P0=NixieTable[Number]; //段码输出 Delay(1); //显示一段时间 P0=0x00; //段码清0,消影 } void main() { while(1) { Nixie(1,1); //在数码管的第1位置显示1 // Delay(500); Nixie(2,2); //在数码管的第2位置显示2 // Delay(20); Nixie(3,3); //在数码管的第3位置显示3 // Delay(20); } }
数码管显示123456
main.c文件
#include <REGX52.H> #include "Delay.h" //包含Delay头文件 #include "Nixie.h" //包含数码管头文件 void main() { while(1) { Nixie(1,1); //在数码管的第1位置显示1 Nixie(2,2); //在数码管的第2位置显示2 Nixie(3,3); //在数码管的第3位置显示3 Nixie(4,4); //在数码管的第4位置显示4 Nixie(5,5); //在数码管的第5位置显示5 Nixie(6,6); //在数码管的第6位置显示6 } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
//延时子函数
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
Nixie.h文件
#ifndef __NIXIE_H__
#define __NIXIE_H__
void Nixie(unsigned char Location,Number);
#endif
Nixie.c文件
#include <REGX52.H> #include "Delay.h" //包含Delay头文件 //数码管段码表 unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数码管显示子函数 void Nixie(unsigned char Location,Number) { switch(Location) //位码输出 { case 1:P2_4=1;P2_3=1;P2_2=1;break; case 2:P2_4=1;P2_3=1;P2_2=0;break; case 3:P2_4=1;P2_3=0;P2_2=1;break; case 4:P2_4=1;P2_3=0;P2_2=0;break; case 5:P2_4=0;P2_3=1;P2_2=1;break; case 6:P2_4=0;P2_3=1;P2_2=0;break; case 7:P2_4=0;P2_3=0;P2_2=1;break; case 8:P2_4=0;P2_3=0;P2_2=0;break; } P0=NixieTable[Number]; //段码输出 Delay(1); //显示一段时间 P0=0x00; //段码清0,消影 }
main.c文件
#include <REGX52.H> #include "LCD1602.h" //包含LCD1602头文件 #include "Delay.h" //包含Delay头文件 int Result=0; void main() { LCD_Init(); LCD_ShowString(1,1,"helloworld"); while(1) { Result++; //Result自增 Delay(1000); //延时1秒 LCD_ShowNum(2,2,Result,3); //在LCD的1行1列显示Result,长度为3位 } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
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);
#endif
LCD1602.c文件
#include <REGX52.H> //引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^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_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602写数据 * @param Data 要写入的数据 * @retval 无 */ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602设置光标位置 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @retval 无 */ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } } /** * @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(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } } /** * @brief 返回值=X的Y次方 */ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } } /** * @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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }
main.c文件
#include <REGX52.H> #include "Delay.h" //包含Delay头文件 #include "LCD1602.h" //包含LCD1602头文件 #include "MatrixKey.h" //包含矩阵键盘头文件 unsigned char KeyNum; void main() { LCD_Init(); //LCD初始化 LCD_ShowString(1,1,"MatrixKey:"); //LCD显示字符串 while(1) { KeyNum=MatrixKey(); //获取矩阵键盘键码 if(KeyNum) //如果有按键按下 { LCD_ShowNum(2,1,KeyNum,2); //LCD显示键码 } } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
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);
#endif
LCD1602.c文件
#include <REGX52.H> //引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^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_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602写数据 * @param Data 要写入的数据 * @retval 无 */ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602设置光标位置 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @retval 无 */ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } } /** * @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(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } } /** * @brief 返回值=X的Y次方 */ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } } /** * @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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }
Matrix.h文件
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
Matrix.c文件
#include <REGX52.H> #include "Delay.h" /** * @brief 矩阵键盘读取按键键码 * @param 无 * @retval KeyNumber 按下按键的键码值 如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0 */ //按列进行读 unsigned char MatrixKey() { unsigned char KeyNumber=0; P1=0xFF; P1_3=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;} P1=0xFF; P1_2=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;} P1=0xFF; P1_1=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;} P1=0xFF; P1_0=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;} return KeyNumber; }
main.c文件
#include <REGX52.H> #include "Delay.h" #include "LCD1602.h" #include "MatrixKey.h" unsigned char KeyNum; unsigned int Password,Count; void main() { LCD_Init(); LCD_ShowString(1,1,"Password:"); while(1) { /* 1.S1~S10按键按下,输入密码 2.S11按键按下,确认,如果密码正确,OK,如果密码正确,ERR 3.S12按键按下,取消,即当你未按到4位时,按下此按键都会清零 */ KeyNum=MatrixKey(); if(KeyNum) { if(KeyNum<=10) //如果S1~S10按键按下,输入密码 { if(Count<4) //如果输入次数小于4 { Password*=10; //密码左移一位 x*10+当前按得数值 Password+=KeyNum%10; //获取一位密码 十位 百位 千位 Count++; //计次加一 } LCD_ShowNum(2,1,Password,4); //更新显示 } if(KeyNum==11) //如果S11按键按下,确认 { if(Password==2345) //如果密码等于正确密码 { LCD_ShowString(1,14,"OK "); //显示OK Password=0; //密码清零 Count=0; //计次清零 LCD_ShowNum(2,1,Password,4); //更新显示 } else //否则 { LCD_ShowString(1,14,"ERR"); //显示ERR Password=0; //密码清零 Count=0; //计次清零 LCD_ShowNum(2,1,Password,4); //更新显示 } } if(KeyNum==12) //如果S12按键按下,取消 { Password=0; //密码清零 Count=0; //计次清零 LCD_ShowNum(2,1,Password,4); //更新显示 } } } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
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);
#endif
LCD1602.c文件
#include <REGX52.H> //引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^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_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602写数据 * @param Data 要写入的数据 * @retval 无 */ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602设置光标位置 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @retval 无 */ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } } /** * @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(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } } /** * @brief 返回值=X的Y次方 */ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } } /** * @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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }
Matrix.h文件
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
Matrix.c文件
#include <REGX52.H> #include "Delay.h" /** * @brief 矩阵键盘读取按键键码 * @param 无 * @retval KeyNumber 按下按键的键码值 如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0 */ //按列进行读 unsigned char MatrixKey() { unsigned char KeyNumber=0; P1=0xFF; P1_3=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;} P1=0xFF; P1_2=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;} P1=0xFF; P1_1=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;} P1=0xFF; P1_0=0; if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;} if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;} if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;} if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;} return KeyNumber; }
结果如下:
51单片机中断细节参考:http://t.csdn.cn/clOsm
STC-ISP软件设置
main.c
#include <REGX52.H> #include "Timer0.h" #include "Key.h" #include <INTRINS.H> unsigned char KeyNum,LEDMode; void main() { //P2=0xFE; Timer0Init(); while(1) { } } void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; //T0Count计次,对中断频率进行分频 if(T0Count>=1000)//分频500次,500ms { T0Count=0; P2_0=~P2_0; } }
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Timer0.c
#include <REGX52.H> /** * @brief 定时器0初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ void Timer0Init(void) { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 低四位 TH0 = 0xFC; //设置定时初值 高四位 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0=1; EA=1; PT0=0; } /*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=1000) { T0Count=0; } } */
Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
Key.c
#include <REGX52.H> #include "Delay.h" /** * @brief 获取独立按键键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */ unsigned char Key() { unsigned char KeyNumber=0; if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;} if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;} if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;} if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;} return KeyNumber; }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
main.c
#include <REGX52.H> #include "Timer0.h" #include "Key.h" #include <INTRINS.H> unsigned char KeyNum,LEDMode; void main() { P2=0xFE; Timer0Init(); while(1) { KeyNum=Key(); //获取独立按键键码 if(KeyNum) //如果按键按下 { if(KeyNum==1) //如果K1按键按下 { LEDMode++; //模式切换 if(LEDMode>=2)LEDMode=0; } } } } void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; //T0Count计次,对中断频率进行分频 if(T0Count>=500)//分频500次,500ms { T0Count=0; if(LEDMode==0) //模式判断 P2=_crol_(P2,1); //LED输出 左移 if(LEDMode==1) P2=_cror_(P2,1); //右移 } }
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Timer0.c
#include <REGX52.H> /** * @brief 定时器0初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ void Timer0Init(void) { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 低四位 TH0 = 0xFC; //设置定时初值 高四位 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0=1; EA=1; PT0=0; } /*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=1000) { T0Count=0; } } */
Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
Key.c
#include <REGX52.H> #include "Delay.h" /** * @brief 获取独立按键键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */ unsigned char Key() { unsigned char KeyNumber=0; if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;} if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;} if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;} if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;} return KeyNumber; }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
main.c文件
#include <REGX52.H> #include "Delay.h" #include "LCD1602.h" #include "Timer0.h" unsigned char Sec=55,Min=59,Hour=23; void main() { LCD_Init(); Timer0Init(); LCD_ShowString(1,1,"Clock:"); //上电显示静态字符串 LCD_ShowString(2,1," : :"); while(1) { LCD_ShowNum(2,1,Hour,2); //显示时分秒 LCD_ShowNum(2,4,Min,2); LCD_ShowNum(2,7,Sec,2); } } void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=1000) //定时器分频,1s { T0Count=0; Sec++; //1秒到,Sec自增 if(Sec>=60) { Sec=0; //60秒到,Sec清0,Min自增 Min++; if(Min>=60) { Min=0; //60分钟到,Min清0,Hour自增 Hour++; if(Hour>=24) { Hour=0; //24小时到,Hour清0 } } } } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Timer0.c
#include <REGX52.H> /** * @brief 定时器0初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ void Timer0Init(void) { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 低四位 TH0 = 0xFC; //设置定时初值 高四位 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0=1; EA=1; PT0=0; } /*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=1000) { T0Count=0; } } */
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);
#endif
LCD1602.c文件
#include <REGX52.H> //引脚配置: sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^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_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602写数据 * @param Data 要写入的数据 * @retval 无 */ void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); } /** * @brief LCD1602设置光标位置 * @param Line 行位置,范围:1~2 * @param Column 列位置,范围:1~16 * @retval 无 */ void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } } /** * @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(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } } /** * @brief 返回值=X的Y次方 */ int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } } /** * @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(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } } /** * @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(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }
波特率计算
main.c文件
#include <REGX52.H> #include "Delay.h" #include "UART.h" unsigned char Sec; void main() { UART_Init(); //串口初始化 while(1) { UART_SendByte(Sec); //串口发送一个字节 Sec++; //Sec自增 Delay(1000); //延时1秒 } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
UART.h文件
#ifndef __UART_H__
#define __UART_H__
void UART_Init();
void UART_SendByte(unsigned char Byte);
#endif
UART.c文件
#include <REGX52.H> /** * @brief 串口初始化,4800bps@12.000MHz * @param 无 * @retval 无 */ void UART_Init() { SCON=0x40; PCON |= 0x80; TMOD &= 0x0F; //设置定时器模式 TMOD |= 0x20; //设置定时器模式 TL1 = 0xF3; //设定定时初值 TH1 = 0xF3; //设定定时器重装值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 } /** * @brief 串口发送一个字节数据 * @param Byte 要发送的一个字节数据 * @retval 无 */ void UART_SendByte(unsigned char Byte) { SBUF=Byte; while(TI==0); TI=0; }
main.c文件
#include <REGX52.H> #include "Delay.h" #include "UART.h" void main() { UART_Init(); //串口初始化 while(1) { } } void UART_Routine() interrupt 4 { if(RI==1) //如果接收标志位为1,接收到了数据 { /*SBUF是指串行口中的两个缓冲寄存器,一个是发送寄存器,一个是接收寄存器, 在物理结构上是完全独立的,但地址是重叠的。它们都是字节寻址的寄存器, 字节地址均为99H。*/ P2=~SBUF; //从电脑上位机读取数据,然后发给单片机,取反后输出到LED,SBUF是串口自定义的 UART_SendByte(SBUF); //将受到的数据发回串口,即发回电脑 RI=0; //接收标志位清0 } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
UART.h文件
#ifndef __UART_H__
#define __UART_H__
void UART_Init();
void UART_SendByte(unsigned char Byte);
#endif
UART.c文件
#include <REGX52.H> /** * @brief 串口初始化,4800bps@12.000MHz * @param 无 * @retval 无 */ void UART_Init() { SCON=0x40; PCON |= 0x80; TMOD &= 0x0F; //设置定时器模式 TMOD |= 0x20; //设置定时器模式 TL1 = 0xF3; //设定定时初值 TH1 = 0xF3; //设定定时器重装值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 } /** * @brief 串口发送一个字节数据 * @param Byte 要发送的一个字节数据 * @retval 无 */ void UART_SendByte(unsigned char Byte) { SBUF=Byte; while(TI==0); TI=0; }
main.c文件
#include <REGX52.H> #include "Delay.h" sbit RCK=P3^5; //RCLK sbit SCK=P3^6; //SRCLK sbit SER=P3^4; //SER #define MATRIX_LED_PORT P0 /** * @brief 74HC595写入一个字节 * @param Byte 要写入的字节 * @retval 无 */ void _74HC595_WriteByte(unsigned char Byte) { unsigned char i; /*74HC595是串行输入并行输出的移位寄存器,可用3根线输入串行数据, 8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于IO口扩展。*/ for(i=0;i<8;i++) { SER=Byte&(0x80>>i); //向移位寄存器输8位数据 SCK=1; SCK=0; } RCK=1; //上升沿锁存 RCLK 置1,把数据传过去 RCK=0; //上升沿锁存 RCLK 用完后置0 } /** * @brief LED点阵屏显示一列数据 * @param Column 要选择的列,范围:0~7,0在最左边 * @param Data 选择列显示的数据,高位在上,1为亮,0为灭 * @retval 无 */ void MatrixLED_ShowColumn(unsigned char Column,Data) { //段选 位选 延时 位清零 段选 位选 延时 位清零 ...... _74HC595_WriteByte(Data); //负责传LED另一端电平 MATRIX_LED_PORT=~(0x80>>Column); //P0口高低电平,负责传LED一端电平 Delay(1); MATRIX_LED_PORT=0xFF; } void main() { SCK=0; RCK=0; while(1) { MatrixLED_ShowColumn(0,0x3C); MatrixLED_ShowColumn(1,0x42); MatrixLED_ShowColumn(2,0xA9); MatrixLED_ShowColumn(3,0x85); MatrixLED_ShowColumn(4,0x85); MatrixLED_ShowColumn(5,0xA9); MatrixLED_ShowColumn(6,0x42); MatrixLED_ShowColumn(7,0x3C); } }
Delay.h文件
Delay.c文件
main.c文件
#include <REGX52.H> #include "Delay.h" #include "MatrixLED.h" //动画数据 unsigned char code Animation[]={ 0x3C,0x42,0xA9,0x85,0x85,0xA9,0x42,0x3C, 0x3C,0x42,0xA1,0x85,0x85,0xA1,0x42,0x3C, 0x3C,0x42,0xA5,0x89,0x89,0xA5,0x42,0x3C, }; void main() { unsigned char i,Offset=0,Count=0; MatrixLED_Init(); while(1) { for(i=0;i<8;i++) //循环8次,显示8列数据 { /** * @brief LED点阵屏显示一列数据 * @param Column 要选择的列,范围:0~7,0在最左边 * @param Data 选择列显示的数据,高位在上,1为亮,0为灭 * @retval 无 */ MatrixLED_ShowColumn(i,Animation[i+Offset]); } Count++; //计次延时,延时的作用,也可以换成演示器 if(Count>15) { Count=0; Offset+=8; //偏移+8,切换下一帧画面 if(Offset>16) //24>16,去到最后一次的前8位 { Offset=0; } } } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
MatrixLED.h文件
#ifndef __MATRIX_LED_H__
#define __MATRIX_LED_H__
void MatrixLED_Init();
void MatrixLED_ShowColumn(unsigned char Column,Data);
#endif
MatrixLED.c文件
#include <REGX52.H> #include "Delay.h" sbit RCK=P3^5; //RCLK sbit SCK=P3^6; //SRCLK sbit SER=P3^4; //SER #define MATRIX_LED_PORT P0 /** * @brief 74HC595写入一个字节 * @param Byte 要写入的字节 * @retval 无 */ void _74HC595_WriteByte(unsigned char Byte) { unsigned char i; for(i=0;i<8;i++) { SER=Byte&(0x80>>i); SCK=1; SCK=0; } RCK=1; RCK=0; } /** * @brief 点阵屏初始化 * @param 无 * @retval 无 */ void MatrixLED_Init() { SCK=0; RCK=0; } /** * @brief LED点阵屏显示一列数据 * @param Column 要选择的列,范围:0~7,0在最左边 * @param Data 选择列显示的数据,高位在上,1为亮,0为灭 * @retval 无 */ void MatrixLED_ShowColumn(unsigned char Column,Data) { _74HC595_WriteByte(Data); MATRIX_LED_PORT=~(0x80>>Column); Delay(1); MATRIX_LED_PORT=0xFF; }
main.c文件
#include <REGX52.H> #include "LCD1602.h" #include "DS1302.h" void main() { LCD_Init(); DS1302_Init(); LCD_ShowString(1,1," - - ");//静态字符初始化显示 LCD_ShowString(2,1," : : "); 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);//显示秒 } }
Delay.h文件
Delay.c文件
LCD1602.h文件
LCD1602.c文件
DS1302.h文件
#ifndef __DS1302_H__
#define __DS1302_H__
//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期
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.c文件
#include <REGX52.H> //引脚定义 sbit DS1302_SCLK=P3^6; sbit DS1302_IO=P3^4; sbit DS1302_CE=P3^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分别为年、月、日、时、分、秒、星期 unsigned char DS1302_Time[]={19,11,16,12,59,55,6}; /** * @brief DS1302初始化 * @param 无 * @retval 无 */ void DS1302_Init(void) { DS1302_CE=0; DS1302_SCLK=0; } /** * @brief DS1302写一个字节 * @param Command 命令字/地址 * @param Data 要写入的数据 * @retval 无 */ void DS1302_WriteByte(unsigned char Command,Data) { unsigned char i; DS1302_CE=1; //走R/W| A0| A1| A2| A3 A4 RC| 1 这一步 for(i=0;i<8;i++) { DS1302_IO=Command&(0x01<<i);//把Command的各位取出来 DS1302_SCLK=1; DS1302_SCLK=0; } //走D0|D1D2|D3|D4|D5|D6|D7这一步 for(i=0;i<8;i++) { DS1302_IO=Data&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0; } DS1302_CE=0; } /** * @brief DS1302读一个字节 * @param Command 命令字/地址 * @retval 读出的数据 */ unsigned char DS1302_ReadByte(unsigned char Command) { unsigned char i,Data=0x00; Command|=0x01; //将指令转换为读指令 DS1302_CE=1; for(i=0;i<8;i++) { DS1302_IO=Command&(0x01<<i); DS1302_SCLK=0; DS1302_SCLK=1; } for(i=0;i<8;i++) { DS1302_SCLK=1; DS1302_SCLK=0; if(DS1302_IO){Data|=(0x01<<i);} } DS1302_CE=0; DS1302_IO=0; //读取后将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*16+DS1302_Time[0]%10);//十进制转BCD码后写入 DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10); DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10); DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10); DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10); DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10); DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10); DS1302_WriteByte(DS1302_WP,0x80); } /** * @brief DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中 * @param 无 * @retval 无 */ void DS1302_ReadTime(void) { unsigned char Temp; Temp=DS1302_ReadByte(DS1302_YEAR); DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取 Temp=DS1302_ReadByte(DS1302_MONTH); DS1302_Time[1]=Temp/16*10+Temp%16; Temp=DS1302_ReadByte(DS1302_DATE); DS1302_Time[2]=Temp/16*10+Temp%16; Temp=DS1302_ReadByte(DS1302_HOUR); DS1302_Time[3]=Temp/16*10+Temp%16; Temp=DS1302_ReadByte(DS1302_MINUTE); DS1302_Time[4]=Temp/16*10+Temp%16; Temp=DS1302_ReadByte(DS1302_SECOND); DS1302_Time[5]=Temp/16*10+Temp%16; Temp=DS1302_ReadByte(DS1302_DAY); DS1302_Time[6]=Temp/16*10+Temp%16; }
main.c文件
#include <REGX52.H> #include "LCD1602.h" #include "DS1302.h" #include "Key.h" #include "Timer0.h" /*按键1:切换显示模式还是调节模式 按键2:切换屏幕数字位置,选择时分秒 按键3:调节增加数字 按键4:减小增加数字 */ unsigned 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(KeyNum==2)//按键2按下 { TimeSetSelect++;//设置选择位加1 TimeSetSelect%=6;//越界清零 } if(KeyNum==3)//按键3按下 { DS1302_Time[TimeSetSelect]++;//时间设置位数值加1 if(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]%4==0) { 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(KeyNum==4)//按键4按下 { DS1302_Time[TimeSetSelect]--;//时间设置位数值减1 if(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]%4==0) { 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(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");} //数字,不显示 交叉显示 else {LCD_ShowNum(1,1,DS1302_Time[0],2);} if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");} else {LCD_ShowNum(1,4,DS1302_Time[1],2);} if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");} else {LCD_ShowNum(1,7,DS1302_Time[2],2);} if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");} else {LCD_ShowNum(2,1,DS1302_Time[3],2);} if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");} else {LCD_ShowNum(2,4,DS1302_Time[4],2);} if(TimeSetSelect==5 && TimeSetFlashFlag==1){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) { KeyNum=Key();//读取键码 if(KeyNum==1)//按键1按下 { if(MODE==0){MODE=1;TimeSetSelect=0;}//功能切换 MODE=0,显示 MODE=1,设置 else if(MODE==1){MODE=0;DS1302_SetTime();} } /*1.break语句的使用场合主要是switch语句和循环结构。在循环结构中使用break语句, 如果执行了break语句,那么就退出循环,接着执行循环结构下面的第一条语句。 如果在多重嵌套循环中使用break语句,当执行break语句的时候,退出的是它所在的循环结构, 对外层循环没有任何影响。如果循环结构里有switch语句,并且在switch语句中使用了break语句, 当执行switch语句中的break语句时,仅退出switch语句,不会退出外面的循环结构。 2.continue语句是这5种结束循环的方式中最特殊的,因为它并没有真的退出循环, 而是只结束本次循环体的执行,所以在使用continue的时候要注意这一点。*/ 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(T0Count>=500)//每500ms进入一次 { T0Count=0; TimeSetFlashFlag=!TimeSetFlashFlag;//闪烁标志位取反 } }
Delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c文件
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
LCD1602.h文件
LCD1602.c文件
DS1302.h文件
DS1302.c文件
Key.h文件
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
Key.c文件
#include <REGX52.H> #include "Delay.h" /** * @brief 获取独立按键键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */ unsigned char Key() { unsigned char KeyNumber=0; if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;} if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;} if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;} if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;} return KeyNumber; }
Timer0.h文件
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Timer0.c文件
#include <REGX52.H> /** * @brief 定时器0初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ void Timer0Init(void) { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0=1; EA=1; PT0=0; } /*定时器中断函数模板 void Timer0_Routine() interrupt 1 { static unsigned int T0Count; TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=1000) { T0Count=0; } } */
字节高低位:
一般左边为高位 右边为低位(这个高低来自于人类的阅读习惯,数字从左向右,表示由大到小)
一般一个16位(双字节)的数据,比如 FF1A (16进制)
那么高位字节就是FF,低位是1A
如果是32位的数据,比如 3F68415B
高位字(不是字节)是3F68
低位字是415B
右边是低位位,左边是高位(人的阅读习惯)
参考链接:http://t.csdn.cn/x355H
I2C协议规定在数据传输过程中,只允许在SCL位低电平时更改SDA的状态,在SCL位高电平期间必须保持SDA的稳定(否则会被误认为时起始或终止信号)。
发送(写)一个字节的过程为:当SCL为低电平时,主机更改SDA(准备要传输的数据),当SCL为高电平时,数据发送给从机,这样传输的时一个高电平(1)或是一个低电平(0),即按位从高位到低位,从左到右传送(读也是按位从高到低读)。
参考链接:http://t.csdn.cn/eZWpG
参考链接:http://t.csdn.cn/N3LMj
单片机的C语言中位操作用法
参考链接:http://t.csdn.cn/c7rUt
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。