51单片机开发——day01

1、软件安装:

2、单片机(Micro Controller Unit)MCU:

        内部集成了cpu,RAM,ROM,定时器,中断系统,通讯接口,

        用于信息采集处理硬件设备控制;

8051内核所以带了这个内核的单片机都叫51单片机(是所有兼容8031指令系统的单片机统称);

本次学习使用的单片机信息:

3、单片机命名规则:

4、单片机89c52结构

5、LED

TTL电平:高电平5V,低电平0V

寄存器(p2)以8个为单位分组,对应八个IO口,cpu通过配置寄存器的01来控制IO口的高低电平;

编程中用16进制表示,

点亮LED:单片机的晶振不会停,P2会一直工作;

增加循环,让程序停止在循环里,P2不会重复工作;

LED闪烁:

LED流水灯:

        

独立按键控制LED:

按键开关的抖动:

        

按键消抖:可以用触发器过滤,也可以延迟消抖;

独立按键控制LED表示二进制:

独立按键控制LED移位

数码管:

共阴极和共阳极数码管原理图,本次学习使用共阴极数码管;

        

双向缓冲器(把单片机的驱动信号改成控制型号,利用缓冲器去放大高电平达到更好的驱动效果):

LE是跳线帽:把LE接到高电平VCC,LE接到高电平,就保证P00(A0)输入什么B0就接收什么;

(在单片机中高电平的驱动能力有限,其输出的最大电流不能太大,低电平驱动能力强一些,所以采用低电平点亮LED。)

电容正常为皮法拉(pf):

采用电容来保证电路的稳定(电源滤波);

一般情况下数码管由于IO输入端的接口为相同值,所以一般显示相同的值,要实现动态数码管显示可以采用快速切换数字的方法,由于晶振频率的原因,程序执行一遍人眼看不出来,所以可以通过不断执行程序语句来实现动态数码管显示;

74LS138译码器:输入为CBA,输出为Y0-Y7;

静态数码管代码实现:

数码管消影(在段选后把段选清零):

        位选,段选,...()

清零方法在段选后延迟1ms,然后把P0清零;

数码管的驱动方式:

代码实现:

#include <REGX52.H>
#include <../headFile/at89c52.h>
unsigned 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: //
            P2_4 = 1;
            P2_3 = 1;
            P2_2 = 1;
            break;
        case 2: //LED7
            P2_4 = 1;
            P2_3 = 1;
            P2_2 = 0;
            break;
        case 3: //LED6
            P2_4 = 1;
            P2_3 = 0;
            P2_2 = 1;
            break;
        case 4:  //LED5
            P2_4 = 1;
            P2_3 = 0;
            P2_2 = 0;
            break;
        case 5:  //LED4
            P2_4 = 0;
            P2_3 = 1;
            P2_2 = 1;
            break;
        case 6:  //LED3
            P2_4 = 0;
            P2_3 = 1;
            P2_2 = 0;
            break;
        case 7:  //LED2
            P2_4 = 0;
            P2_3 = 0;
            P2_2 = 1;
            break;
        case 8:  //LED1
            P2_4 = 0;
            P2_3 = 0;
            P2_2 = 0;
            break;
        }
        P0 = NixieTable[Number];
        Delay(1);
        P0 = 0x00;
}
void main()
{
    while(1){
        Nixie(1,0);
        Nixie(2,1);
        Nixie(3,2);
        Nixie(4,3);
        Nixie(5,4);
        Nixie(6,5);
        Nixie(7,6);
        Nixie(8,7);
        }
    }

模块化编程(提高代码可阅读性,可维护性,可移植性):

 LCD1602调试工具:

使用LCD后会和数码管和LED引脚冲突:

#include <REGX52.H>
#include "LCD1602.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');
    }
}
 

c语言预编译:

矩阵键盘(为了减少IO口的占用):

矩阵按键每一行类似于独立按键;

如果逐行扫描在51开发板中矩阵键盘的IO口会和其他外设产生引脚冲突,例如矩阵键盘的P15口就与蜂鸣器的BZ口冲突,逐行扫描后会导致蜂鸣器一直响;

矩阵键盘密码锁:

        

IO口的模式(模式可以定制):

准双向口输入配置:

弱上拉,强下拉(单片机高电平驱动能力弱)单片机的IO口可以双向输出输入,假如一个IO口给1在独路给0,也不会短路,

高电平的驱动能力弱于低电平驱动能力;

开漏输出:

扫描:

        数码管扫描(输出扫描)

原理:显示第一位——显示第二位——显示第三位——。。。快速循环这个过程,最终实现数码管同时显示的效果;

矩阵键盘(输入扫描)

原理:读取第一行(列)——读取第二行列——读取第三行列。。。快速循环这个过程,最终实现所有按键同时检测的效果;

(视频显示像素点如果不采用矩阵扫描会导致需要大量的IO口,采用矩阵扫描可以极大节约IO口数量)

以上扫描的共性:节省IO口;

定时器:

     51单片机定时器属于单片机内部资源,电路连接和运转均在单片机内部完成;

用于计时系统,软件计时,使得程序固定时间完成一项操作;

        替代长时间Delay,提高cpu运行效率和处理速度;

多任务执行:把程序切换成时间片穿插在一条时间线上;

        STC89C52有(T0,T1,T2)三个定时器,T0与T1与传统的51兼容,T2时此型号单片机增加的资源;

定时器在单片机内部根据时钟的输出信号,每隔固定时间段,计数器单元的数值就增加1,计数器单元值增加的设定的提醒时间时,计数单元就会向中断系统发出中断申请,产生提醒,使程序跳转到中断服务函数中执行;

        时钟(提供计数单元的时钟脉冲) ----------计数单元(时钟计数)---------中断系统(产生中断,执行定时任务)

定时器的工作模式:

        STC89C52的T0和T1都有的四种工作模式:

模式0:13位定时器/计数器

模式1:16位定时器/计数器(常用)

模式2:8位自动重装模式

模式3:两个8位计数器

高字节TH,低字节TL;这个计数器只能数到(0---65535);unsigned int

溢出时计数器会清零,并申请中断;只有两个字节存定时器计数情况;

定时器时钟:

该时钟可以由内部引脚提供(该计数器就是时钟),也可以从外部引脚提供(该计数器就充当计数器的功能)

        SYSclk:系统时钟,即晶振周期,本开发板12MHZ

在振荡器中采用一个特殊的元件——石英晶体,可以产生高度稳定的信号,这种采用石英晶体的振荡器称为晶体振荡器。

定时器中断系统:

        

        高优先级中断可以打断低优先级中断;

中断相当于可以同时执行多个任务;

STC89C52中断资源:

单片机通过配置寄存器来控制内部线路的连接,通过内部线路的不同连接方式来实现不同的功能;

按键控制LED控制流水灯模式:

        定时器开启,12M的晶振1微秒加一,加到最大值才产生中断;总共定时65535微秒;

64535离计数器溢出差值1000,所以计时时间为1ms,(给计数器赋值,多次产生中断,直到达到目标时间);

        1、配置TMOD(寄存器)工作模式

配置定时器0的低四位

TMOD是不可寻址寄存器,如果只给低四位赋值时,只用一个定时器的情况下没有影响,如果要用两个定时器,只赋值低四位会导致赋值刷新另一个定时器的参数IO,导致定时器功能无法正常使用;(可以用与或赋值,避免上述情况)

    TMOD = TMOD & 0xF0;//把TMOD的低四位清零,高四位保持不变

    TMOD = TMOD | 0x01;//把TMOD的低四位置一,高四位不变;

让定时器在模式1工作所以在M1给0,M0给1,C/T给0,GATE给0,

M1和M0共同决定定时器的工作模式,门控端GATE给0就是int0单独控制;

可位寻址寄存器可以对每一位单独赋值,不可位寻址的寄存器不能单独赋值,只能单独赋值;

TF0 = 0;把TF0清零防止配置好就产生中断;

TR0 = 1;定时器是否开启,TR0给1允许T0开始计数,TR0=0时禁止T0计数;(GATE = 0);

IE0  ;控制外部中断引脚,

IT0  ;控制外部中断引脚,                                                                                                                                                                                                                                                                                 

配置中断:

ET0 = 1 ;

EA =1;

PT0 =0;                                                                                                                                           

配置好中断后写入中断任务子函数(中断子程序):

                                                

  • 37
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值