2017-03-04 13:21:26 sinat_32582203 阅读数 451
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

编写程序,在Led阵列上依次循环显示自己的学号及姓名拼音的缩写

/*******************************************************************************
* 标    题: LED点阵显示
* 功能描述: LED点阵循环显示"141270049ZRJ"
*******************************************************************************/
#include <htc.h>

#define uint8 unsigned char
#define uint16 unsigned int

__CONFIG(FOSC_HS &WDTE_OFF &BOREN_OFF &PWRTE_OFF &LVP_OFF); //设置配置位
//WDTE_OFF:disable watchdog timer       看门狗禁止
//LVP_OFF:low voltage programming disabled  低电压编程禁止
//FOSC_HS:high speed crystal/resonator  4M以上晶振选择HS高速
//PWRTDIS:disable power up timer
//BOREN_OFF:disable brown out reset

#define     SCK_595     RA5
#define     RCK_595     RE0
#define     SER_595     RC0

void DelayUS(uint8 delay);
void HC595_Init(void);
void HC595_Write_Byte(uint8 data);
uint8 LED_Datachage(uint8 data);

const uint8 dot[12][8] =
{
    {0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x00},   //"1"
    {0x00, 0x08, 0x18, 0x28, 0x7E, 0x08, 0x08, 0x00},   //"4"
    {0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x00},   //"1"
    {0x00, 0x18, 0x24, 0x08, 0x10, 0x3C, 0x00, 0x00},   //"2"
    {0x00, 0x3C, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00},   //"7"
    {0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00},   //"0"
    {0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00},   //"0"
    {0x00, 0x08, 0x18, 0x28, 0x7E, 0x08, 0x08, 0x00},   //"4"
    {0x00, 0x18, 0x24, 0x24, 0x1C, 0x08, 0x10, 0x00},   //"9"
    {0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00},   //"Z"
    {0x00, 0x70, 0x48, 0x70, 0x60, 0x50, 0x48, 0x00},   //"R"
    {0x00, 0x7C, 0x10, 0x10, 0x10, 0x50, 0x20, 0x00}    //"J"
};

/*******************************************************************************
* 函 数 名: DelayUS(uint8 delay)
* 函数功能: 微秒延时   for 20MHZ
* 入口参数: delay
* 返    回: 无
*******************************************************************************/

void DelayUS(uint8 delay)
{
    while(--delay);
}

/******************************************************************************
* 函 数 名: HC595_Init(void)
* 函数功能: 74HC595初始化
* 入口参数: 无
* 返    回: 无
*******************************************************************************/
void HC595_Init(void)
{
    ADCON1 = 0x8E;
    TRISA5 = 0;
    TRISE0 = 0;
    TRISC0 = 0;
}

/******************************************************************************
* 函 数 名: HC595_Write_Byte(uint8 data)
* 函数功能: 74HC595写8位数据
* 入口参数: 无
* 返    回: 无
*******************************************************************************/
void HC595_Write_Byte(uint8 data)
{
    uint8 i;
    for(i = 0; i < 8; i++)
    {
        if(data & 0x80)
        {
            SER_595 = 1;
        }
        else
        {
            SER_595 = 0;
        }
        SCK_595 = 0;
        data <<= 1;
        SCK_595 = 1;
    }
    RCK_595 = 0;
    RCK_595 = 1;
}

/******************************************************************************
* 函 数 名: LED_Datachage(uint8 data)
* 函数功能: 将8位数据的bit0和bit7、bit1和bit6,bit2和bit5,bit3和bit4互相对换
* 入口参数: data:待对换的数据
* 返    回: 无
*******************************************************************************/
uint8 LED_Datachage(uint8 data)
{
    uint8 temp, temp1;
    temp = (data & 0x01) << 7;
    temp1 = (data & 0x80) >> 7;
    data = (data & 0x7E) | temp | temp1;
    temp = (data & 0x02) << 5;
    temp1 = (data & 0x40) >> 5;
    data = (data & 0xBD) | temp | temp1;
    temp = (data & 0x04) << 3;
    temp1 = (data & 0x20) >> 3;
    data = (data & 0xDB) | temp | temp1;
    temp = (data & 0x08) << 1;
    temp1 = (data & 0x10) >> 1;
    data = (data & 0xE7) | temp | temp1;
    return data;
}

/*******************************************************************************
* 函 数 名: main(void)
* 函数功能: LED点阵循环显示0~9数字
*******************************************************************************/
void main(void)
{
    uint8 i, j;
    uint16 k;
    TRISA &= 0xE3;      //RA2、RA3、RA4设置成输出模式
    PORTA |= 0x1C;      //RA2 = 1、RA3 = 1、RA4 = 1,不选通任何数码管,则关掉数码管显示

    TRISE &= 0xEF;      //配置PORTD为普通IO口,对PORTD的操作务必加上这句
    TRISD = 0x00;       //设置PORTD为输出
    HC595_Init();       //74HC595初始化
    while(1)
    {
        for(j = 0; j < 12; j++) //"141270049ZRJ"
        {
            for(k = 0; k < 1500; k++)   //每个数字重复显示次数
            {
                for(i = 0; i < 8; i++)  //8行
                {
                    HC595_Write_Byte((0x01 << i));  //选择行
                    PORTD = ~LED_Datachage(dot[j][i]);  //送字
                    DelayUS(50);    //延时50us
                    PORTD = 0xFF;   //关显示
                }
            }
        }
    }
}
单片机
2013-06-09 22:18:00 a379039233 阅读数 4841
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

      单片机就是一个小的计算机,不过他没有计算机那么好,方便的输入输出设备,计算机的输入设备就是鼠标,键盘等,方便的很,输出设备就是显示器,将输出非常清晰的显示在屏幕上。但是单片机的输入输出都是他的引脚,需要通过编程控制。

       单片机和PC机相同的地方就是都有CPU(我把单片机的微控制器核也叫CPU),内存(单片机的ROM,RAM,FLASH等),时钟系统,中断系统,定时器等等。

      一, 单片机最小系统就是单片机能够运行起来的必要条件:

   1.电源 2.晶振 3.复位电路  没有电源就没有能源,就不能工作;没有晶振,就没有时钟电路,就没有节拍,指令就不能按一定的步调运行;没有复位电路,单片机就很不可靠,会出现“死机”、“程序走飞(PC)”等现象。
   
   二,一些重要概念
    1. 我们对单片机编程不过就是设置单片机内部的寄存器和端口引脚以便输出高低电平控制其他(连接在单片机上)器件而已。
    2. 编程中最重要的是1:配置时钟,2:配置IO口,3:配置复位方式,看门狗设置等等
       次要的是:中断(外部,定时器,串口),串口,ADC,XRAM读写,内部FLASH等。   
    3. 1个机器周期 =12个时钟周期(晶振的振荡周期)   
    4. while(1);让单片机一直工作,等待中断!防止程序跑飞等。
    5. 51单片机共111条汇编指令,
7种寻址方式:
1.立即寻址 MOV A,#01H
2.直接寻址 MOV A,20H
3.寄存器寻址 MOV A,R3(A,B,Cy,DPTR)

4.寄存器间接寻址 MOVA,@R0  R1
5.变址寻址 MOVC  A, @A+DPTR
6.相对寻址 SJMP   rel; (PC)←(PC) + 2(指令长度) +  rel
7.位寻址 位寻址是直接寻址方式的一种,其特点是对8位二进制数中的某一位的地址进行操作。
MOV 00h,C,MOV  20H.0, C  ,PSW.6
 
     6. XRAM(分内外)读写 
      1> XBYTE[address]=data   写数据
         data=XBYTE[address]   读数据;
   2>char xdata *mydat;
      ......
      mydat=(char xdata*)0x0030;
      *mydat=31;
   3>汇编方式
	mov dptr,#1000h
	mov a,#55h
	movx @dptr,a
      7.  读端口信号是必须先向端口写“1”,然后再读,这就是单片机口信号的准双向的含义。切记!
      8.  模拟输入或数字I/O,推挽(强)或漏极开路输出(IO,inout)

 
9. 一些寄存器默认设置即可,配置了可能会有警告。usb clock.clksel=1  10. Keil C 里面Lib库文件的生成与调用,可以自己做lib。
11. ram高128位只能间接寻址。idata,一些人可能没有用到idata,发现data不够用。
12 1s=1000ms=1000000us=1000000000ns.
13.
x M晶振定时 y ms: TH1 = (65536 - (x/12)*y*1000) / 256;     TL1 = (65536 - (x/12)*y*1000) % 256;16位的哦,亲!
假设C8051F020单片机的晶振是22114800Hz,测每秒计22114800个数 经过12分频后,每秒计22114800÷12=1842900个数,如果设置计数器初值是 0xfe90(即十进制65165),则需要计的数的个数为65535-65165=360,那么定时器的 时间为(360÷1842900)(S)≈0.195ms,即0.2ms。
#define uchar unsigned char
#define uint  unsigned int
#define ulong unsigned long #define bool  bit
 
#include<C8051F330.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long //引脚定义
sbit In1= P0^3; sbit In2= P0^7; sbit In3= P1^3; sbit In4= P1^7; sbit Out1= P0^3; sbit Out2= P0^7; sbit Out3= P1^3; sbit Out4= P1^7;
//----------------------------------------------------------------------------- //功能:延时 //入口参数:yc //出口参数:无 //-----------------------------------------------------------------------------
void delay(uint time)
{
  while(--time);
}
//----------------------------------------------------------------------------- //功能:单片机C8051F330初始化 //入口参数:无 //出口参数:无 //-----------------------------------------------------------------------------
void Mcu_Init(void) { 
  PCA0MD&=~0x40;                 //禁止内部看门狗  
  OSCICN = 0x83;                 //内部振荡控制寄存器,使能H-F,八分频  
OSCICL = 0x00;                 //期望输出频率也是24.5MHz
  CLKSEL = 0x00;                  //系统时钟取自内部高频振荡器  
RSTSRC = 0x04;                 //检测到时钟丢失时允许系统复位
}
 
 
//----------------------------------------------------------------------------- //功能:MCU I/O口配置 //入口参数:无 //出口参数:无 //-----------------------------------------------------------------------------
 
void PORT_Init (void) {    
P0MDOUT  = 0x88;                         //P0.3,P0.7推挽输出   
P1MDOUT  = 0x88;                  //P1.3,P1.7推挽输出   
XBR0     = 0x00;  
  XBR1     = 0x40;                  //使能交叉开关和弱上拉 }
//----------------------------------------------------------------------------- // 功能:所有设备初始化 //----------------------------------------------------------------------------- // 入口参数:无 // 出口参数:无 //-----------------------------------------------------------------------------
 
void Init_Device (void) {   
Mcu_Init();   
PORT_Init();
} void main() {
     Init_Device();     
delay(10);          
     while(1){            }
 
}
2018-02-21 10:03:20 plm199513100 阅读数 1376
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

/*
名称:51单片机之数码管显示实验
说明:对于数码管来说,其本质上可以理解为按照一定规则组合的多个二极管。其使用只需按照特定规则显示对应的二极管即可。要稍微注意一点的就是多个数码管的显示分为静态显示和动态显示。静态显示就是每个二极管显示的内容是一样的,通过片选信号来决定是哪个二极管该显示。动态数码管,即利用人眼的视觉停留效果,快速扫描,快速显示每个数码管的内容,使得每个数码管看起来好像是一起显示的一样。
本实验编写了几个数码管显示的简单程序。在此不做赘述了。

*/

#include <reg52.h>

#define uchar unsigned char


//共阳极段码(a在高位,dp在低位)
uchar code _data[16] = {0x03,0x9F,0x25,0x0D,0x99,0x49,0x41,0x1F,0x01,0x09,
                                                0x11,0xC1,0x63,0x85,0x61,0x71
                                                };

//共阳极段码(a在低位,dp在高位)
uchar code _data1[16] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,
                                                0x83,0xC6,0xA1,0x86,0x8E
                                                };                                              

//延时函数
void delay_ms(unsigned int n)
{
    unsigned int i=0,j=0;
    for(i=0;i<n;i++)
        for(j=0;j<123;j++);
}


//一位数码管循环显示0-F(共阳极)
void OneNixieTube()
{
    uchar i = 0;

    while(1)
    {
            for(i = 0;i<16;++i)
            {
                P2 = _data1[i];         
                delay_ms(1000);
            }



    }
}



//静态数码管循环显示0-8
void StaticNixieTube()
{
    uchar i = 0,temp = 0;
    while(1)
    {
            for(i = 0;i<16;++i)
            {

                //片选部分
                if(i%8 == 0)
                    temp = 0x01;
                else
                    temp = temp<<1;
                P0 = ~temp;                    //P0为片选输出端口,低电平有效
                //显示部分
                P2 = ~_data1[i];           //P2为显示输出端口


                delay_ms(1000);
            }
    }

}


//动态数码管显示(0-7,8-F,8个数码管分两次显示)
void DynamicNixieTube()
{
    uchar i = 0;
    unsigned int delay_time = 0;        //0-7 8-F每段的延时时间

    uchar CS[8] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};        //片选码

        while(1)
        {

            if(delay_time++ < 250)
            {
                //0-7段显示
                for(i = 0;i < 8;++i)
                {
                    P0 = CS[i];
                    P2 = ~_data1[i];

                    delay_ms(1);        //延时极小的时间间隔,人眼察觉不出来

                }
            }
            else if(delay_time++ < 500 )        //???都是循环250次,为什么0-7段显示的时间长于8-F段显示的时间???
            {
                //8-F段显示
                for(i = 0;i < 8;++i)
                {
                    P0 = CS[i];
                    P2 = ~_data1[i+8];

                    delay_ms(1);        //延时极小的时间间隔,人眼察觉不出来

                }

            }
            else
                delay_time = 0;                 //重新置零

        }
}


//数码管显示指定时间格式为 HH-MM-SS
void DisplayTime(uchar hour,uchar min,uchar sec)
{
    uchar time[8] = {0};
    uchar i = 0,j = 0;
    uchar CS[8] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};        //片选码


    //获取时间的每位信息
    if(hour >= 0 && hour <=23 )
    {
            time[0] = hour / 10;
            time[1] = hour % 10;

            time[2] = ':';
    }


    if(min >= 0 && min <= 59)
    {
        time[3] = min /10;
        time[4] = min % 10;

        time[5] = ':';

    }

    if(sec >= 0 && sec <= 59)
    {
        time[6] = sec / 10;
        time[7] = sec % 10;
    }


    //显示部分
    for(i = 0;i<7;++i)
    {
            for(i = 0;i < 8;++i)
                {
                    P0 = CS[i];             //片选

                    //显示时间
                    if(i != 2 && i != 5)
                    {
                        j = time[i];
                        P2 =  ~_data1[j];
                    }
                    else                        //显示分隔符‘-’
                    {
                        j = 0xBF;
                        P2 = ~j;
                    }

                    delay_ms(1);        //延时极小的时间间隔,人眼察觉不出来

                }
    }



}


int main()
{
    //  OneNixieTube();
    //  StaticNixieTube();
    //DynamicNixieTube()
        //DisplayTime(12,40,56);




    return 0;
}
2008-01-17 16:15:00 mybirdsky 阅读数 731
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏
2006-05-13 22:32:25

字体变小 字体变大
摘要:需要显示的汉字较多时,单片机系统中的汉字编码非常繁琐。本文介绍一种直接利用PC机的汉字内码作为单片机系统的汉字编码,以简化系统的设计。

关键词:单片机 液晶显示器 29F040 汉字显示

引言

  在现代工业控制和一些智能化仪器仪表中,越来越多的场所需要用点阵图形显示器显示汉字。通常的汉字显示方式是先根据所需要的汉字提取汉字点阵(如16×16点阵),将点阵文件存入ROM,形成新的汉字编码;而在使用时刚需要先根据新的汉字编码组成语句,再由MCU根据新编码提取相应的点阵进行汉字显示。在这种显示方式中,如果使用的流字数量较大或语句较多时,利用汉字的新编码组成语句将是一件十分繁琐而枯燥的工作。针对这种情况,本文提出了一种十分简单的方式——直接利用PC机的汉字内码作为单片机系统的编码。下面以8051单片机系统为例阐述如下:

一、硬件组成

  系统中采用香港精电公司的内置T6963控制器[1]的240128T点阵图形液晶显示器。该显示器1行为240点,能容纳16×16点阵的汉字15个,总列数为128点,能显示8行汉字。为了使用MCU操作可使用1片512KB的存储器(如本系统中的29F040)用来存储全部的国标16×16点阵汉辽、8×16的ASCII码点阵数据以及汉字语句编码数据。为了降低成本和减小体积,对于速度要求不是很高的场合也可采用大容量的串行数据存储器,如AT45DB041B。具体的硬件控制电路如图1所示(与汉字显示无关的电路略)。

  由于29F040的容量为512KB,而5031微控制器只能管理64KB的数据间,所以可将29F040分成16页,每页32KB,占单片机系统数据空间的8000H~0FFFFH(剩余32KB为单片机系统的其他存储器和外设)。页码由单片机的P1.0~P1.3选择。液晶显示器的地址为7FF8H~7FF9H。


二、汉字显示原理及软件设计

  UCDOS软件中的文件HZK16和文件ASC16分别为16×16的国标汉字点阵文件和8×16的ASCII码点阵文件,以二进制格式存储。在文件HZK16中,按汉字区位码从小到大依次存有国标区位码表中的所有汉字,每个汉字占用32个字节,每个区为94个汉字。在文件ASC16中按ASCII码从小到大依次存有8×16的ASCII码点阵,每个ASCII码占用16个字节。

  在PC机的文本文件中,汉字是以机内码的形式存储的,每个汉字占用两个字节:第一个字节为区码,为了与ASCII码区别,范围从十六进制的0A1H开始(小于80H的为ASCII码字符),对应区位码中区码的第一区;第二个字节为位码,范围也是从0A1H开始,对应某区中的第一个位码。这样,将汉字机内码减去0A0AH就得该汉字的区位码。

  例如汉字“房”的机内码为十六进制的“B7BF”,其中“B7”表示区码,“BF”表示位码。所以“房”的区位码为0B7BFH-0A0A0H=171FH。将区码和位码分别转换为十进制得汉字“房”的区位码为“2331”,即“房”的点阵位于第23区的第31个字的位置,相当于在文件HZK16中的位置为第32×[(23-1) ×94+(31-1)]=67136B以后的32个字节为“房”的显示点阵。

  在本单片机系统中,起始地址的高4位为页号,送P1口,低15位为数据区地址,送指针DPTR。利用“MOVX”指令连续取32个字节送LCD的相应位置,就能实现正确的汉字显示。

  ASCII码的显示与汉字的显示基本原理相同。在文件ASC16中不存在机内码的问题,其显示点阵直接按ASCII码从小到大依次排列,只是每个ASCII码在文本文件中只占1个字节且小于80H,而且ASCII码为8×16点阵,所以在ASCII16文件中,每个ASCII码的点阵也只占16个字节。

  首先提取16×16的国标汉字点阵和8×16的ASCII码点阵(如UCDOS软件中的HZK16和ASC16)并将其直接写入29F040。其中HZK16(共256KB)点0~7页。为了便于编程,ASC16虽然只有4KB,也单独占用第8页。其余剩下的空间用来存储汉字语句的编码。

  由于240×128点阵的LED显示器每个只能显示15个汉字(16×16点阵汉字),即30个字节。所以可将需要显示的语句按30个字节为1行进行编写,不足30个字符的则补空格。在PC机上进行录入时,每行30个字符再加上回车键和换行符,实占32个字符。所录入的语句以纯文本形式存盘,再将该文本文件以二进制的形式写入29F040的第9页。那么,以后根据需要显示的语句行号便可以进行正确的显示。此,作者推出荐使用DOS版本的WPS软件的“编辑非文收文件”功能,它能清楚地显示每行是否有30个字符。

根据以上原则,显示1行汉字的具体程序框图如图2所示。

 

为方便读者,将已经在实际应用中中通过的汇编子程序列出如下(关于LCD控制器T6963的用户法请见参考文献1)。

LCDCOM EQU 7FF9H

LCDDAT EQU 7FF8H

;显示1行汉字子程序

;汉字语句位置编号DPTR;行号:R6 PRHZ:MOV 24H,DPH

MOV 25H,DPL

PUSH DPH

PUSH DPL

MOV A,DPH ;计算页号

RR A

RR A

ADD A,#9;从第9区开始存放每行字符的机内码

ORL A,#0F0H

MOV P1,A

LCALL RL245 ;行号乘以32(每行32个字符)

SETB 24H,7 ;数据地址位于8000H~0FFFFH

MOV DPH,24H

MOV DPL,25H

MOV R0,#0E0H

MOV R7,#30 ;连续取出30个字符至0E0H内部数据存储器

PRHZ3:MOVX A,@DPTR

MOV @R0,A

INC R0

INC DPTR

DJNZ R7,PRHZ3

MOV 1DH,#30 ;显示0E0H后的一行字符(共30个)

MOV R5,#0 ;当前列R5

MOV R0,#0E0H

MOV A,#7FH ;是否为ASCII码?

CLR C

SUBB A,@R0

JC DPHZ1

MOV 26H,@R0

INC R0

MOV 24H,R6 ;ASCII码显示

MOV 25H,R5

LCALL PRASCII

SJMP PRHZ4

DPHZ1:MOV 24H,@R0 ;是汉字则将机内码送24H25H

INC R0

MOV 25H,@R0

INC R0

MOV A,25H

CLR C

SUBB A,#0A1H ;机内码转换为二进制的区码和位码

MOV 25H,A

MOV A,24H

CLR C

SUBB A,#0A1H

LCALLDPONHZ ;显示1个汉字

DEC 1DH

INC R5

PRHZ4:INC R5

DJNZ 1DH,PRHZ5

POP DPL

POP DPH

RET

PR0:MOV DPTR,#LCDCOM ;读状态

MOVX A,@DPTR

RET

PR01:LCALLPR0 ;读、写一数据前

JNB ACC.0,PR01

JNB ACC.1,PR01

RET

PR02:LCALL PR0 ;连续读前

JNB ACC.2,PR02

RET

PR03:LCALL PR0 ;连续写前

JNB ACC.3,PR02

RET

PR1:LCALL PR01 ;双字节参数R2,R3

MOV A,R2

LCALL PR14

PR11:LCALL PR01 ;单字节参数R3

MOV A,R3

LCALL PR14

PR12:LCALL PR01 ;无参数指令R4

MOV A,R4

SJMP PR15

PR14:MOV DPTR,#LCDDAT

PR15:MOVX @DPTR,A

RET

RL245:MOV R7,#5 ;24H25H左移5

RLL1:CLR C

MOV A,25H

RLC A

MOV 25H,A

MOV A,24H

RLC A

MOV 24H,A

DJNZ R7,RLL1

RET

;行位置R6(0~7),列位置R5(0~29),汉字区别24H,位码25H

DPONHZ:MOV A,24H ;显示1个汉字

MOV B,#94 ;每区94个汉字

MUL AB

ADD A,25H

MOV 25H,A

CLR A

ADDC A,B

MOV 24H,A

RR A ;获得32KB为1页的页号

RR A

ORL A,#0F0H

MOV P1,A ;页号送P1口

LCALL RL245 ;汉字序号乘以32

SETB 24H,7 ;因为存储器位于单片机系统的7FFFH~0FFFFH

MOV DPH,24H

MOV DPL,25H

MOV R2,#32 ;在该位置连续取出32个字节

MOV R1,#0C0H

DPHZ2:MOVX A,@DPTR

INC DPTR

MOV @R1,A

INC R1

DJNZ R2,DPHZ2

MOV R1,#0C0H

MOV A,R6 ;根据行列位置计算LCD指针

MOV B,#16

MUL AB

MUL B,#30

MUL AB

ADD A,R5

MOV 25H,A

MOV R2,A

CLR A

ADDC A,B

MOV 24H,A

MOV R3,A

MOV 26H,#16 ;将取出的点阵送LCD显示

PRHZ6:MOV R4,#24H

LCALL PR1 ;双字节参数R2,R3

MOV A,@R1

MOV R3,A

INC R1

MOV R4,#0C0H

LCALL PR11 ;单字节参数R3

MOV A,@R1

MOV R3,A

INC R1

MOV R4,#0C0H

LCALL PR11

MOV A,#30

ADD A,25H

MOV R2,A

CLR A

ADDC A,24H

MOV R3,A

MOV 24H,A

DJNZ 26H,PRHZ6

RET

注:由于以上程序直接引自下面的应用实例,调用以上程序时请让寄存器组位于第2区,即R0对应10H。

三、应用实例

  我们应用本文介绍的方法成功地进行了某医疗仪器的设计。该设计要求具有完整的中、英文字符提示和汉字处方显示,并尽可能地为今后的功能扩展和处方修改留有余地。目前仪器中用到的汉字约1200个,语句行为1300行左右,而且用户认为利用工控PC机设计成本过高,要求尽可能地降低成本。显然,对于该系统利用传统的汉字处理方式进行设计虽然能节省一定的存储空间,但庞大的汉字和语句重新编码工作却让人望而生畏,而且当处方修改须要用到新的汉字时相当麻烦。我们利用8051单片机系统和本文介绍的方法进行设计,整个硬件电路和底层程序设计只用了1周的时间,大大地缩短了开周期。而且由于本系统可调用所有的ASCII码和全部汉字库,所以对于功能的扩展和处方的修改十分方便。

2019-10-27 23:06:26 qingwufeiyang12346 阅读数 66
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

本系列教程以AVR单片机为对象,介绍单片机的快速开发方法。

参考教材:《单片机技术及应用项目教程》 栾秋平 电子工业出版社 2019.6 第1版

本文介绍使用74HC595在LED阵列上,显示数字“0”的方法。


一、灯光阵列

二、config.h文件的使用

#ifndef MAIN_H_
#define MAIN_H_

/*
********************************************************************************
调试
********************************************************************************
*/
#define DEBUG 0

/*
********************************************************************************
MSP430器件选择
********************************************************************************
*/
#define MCU_MODULE 0												//0:	支持的芯片:ATmega48_88_168_328
												
/*
********************************************************************************
内部外设配置
********************************************************************************
*/
#define INTERNAL_PERIPHERAL_WDT_MODE			7					//0:	不支持看门狗
																	//1:	15ms
																	//2:	30ms
																	//3:	60ms
																	//4:	120ms
																	//5:	250ms
																	//6:	500ms
																	//7:	1s
																	//8:	2s
																	//9:	4s
																	//10:	8s
																	
#define INTERNAL_PERIPHERAL_UART0_MODE			0x00				//0x00:	不初始化异步串行口0
																	/*----------无效验------偶效验------奇效验------*/
																	//110bps	0x01		0x11		0x21
																	//300bps	0x02		0x12		0x22
																	//600bps	0x03		0x13		0x23
																	//1200bps	0x04		0x14		0x24
																	//2400bps	0x05		0x15		0x25
																	//4800bps	0x06		0x16		0x26
																	//9600bps	0x07		0x17		0x27
																	//14400bps	0x08		0x18		0x28
																	//19200bps	0x09		0x19		0x29
																	//38400bps	0x0A		0x1A		0x2A
																	//56000bps	0x0B		0x1B		0x2B
																	//115200bps	0x0C		0x1C		0x2C

#define INTERNAL_PERIPHERAL_TIMER0_MODE			0					//0:	不初始化TIMER0
																	//1:	定时1ms
																	//2:	将TIEMR0初始化为快速PWM模式,由引脚PD6进行输出

#define INTERNAL_PERIPHERAL_TIMER1_MODE			0					//0:	不初始化TIMER0
																	//1:	定时10ms
																	//2:	定时1ms

#define INTERNAL_PERIPHERAL_ADC_MODE			0					//0:	不使用ADC
																	//1:	使用ADC

#define INTERNAL_PERIPHERAL_INT0_MODE			0					//0:	不使用外部中断0
																	//1:	使用外部中断0
																	
#define INTERNAL_PERIPHERAL_INT1_MODE			0					//0:	不使用外部中断1
																	//1:	使用外部中断1

/*
********************************************************************************
外部模块使用定义
1、部分外围模块定义了使用情况,具体设置内容,应在该外围芯片相应的config文件中进行配置
2、部分外围模块定义了模块使用的个数
********************************************************************************
*/
#define EXTERNAL_MODULE_HC595_MODE				1					//0:	没有使用HC595芯片
																	//1:	使用HC595芯片,其引脚配置在相应的config文件中进行设置
																	//2:	使用HC595芯片,其引脚配置在相应的config文件中进行设置,三个引脚可以使用不同的端口

#define EXTERNAL_MODULE_HC165_MODE				0					//0:	没有使用HC165芯片
																	//1:	使用HC165芯片,其引脚配置在相应的config文件中进行设置
																	//2:   用不同的引脚,操纵两组74HC165

#define EXTERNAL_MODULE_NIXIETUBE_MODE			0					//0:	没有使用数码管及其相关电路
																	//1:	适用于使用1个74HC138芯片和1个74HC595芯片驱动2个LG3641BH的电路
																	//2:	适用于使用14个74HC164驱动14个LGB012BH的电路

#define EXTERNAL_MODULE_SD2405_MODE				0					//0:	没有使用SD2405芯片
																	//1:	使用了SD2405芯片,系统会自动调用IIC总线,使用时应在IIC_config.h中,对IIC进行配置

#define EXTERNAL_MODULE_DS18B20_MODE			0					//0:	没有使用DS18B20芯片
																	//1:	使用了DS18B20芯片

#define EXTERNAL_MODULE_TLC5620_MODE			0					//0:	没有使用TLC5620芯片
																	//1:	使用了TLC5620芯片
																	
#define EXTERNAL_MODULE_CH432T_MODE				0					//0:	没有使用CH432T芯片
																	//1:	使用了CH432T芯片,还应使能相应的外部中断

#define EXTERNAL_MODULE_FM24C64_MODE			0					//0:	没有使用FM24C64芯片
																	//1:	使用了FM24C64芯片,系统会自动调用IIC总线,使用时应在IIC_config.h中,对IIC进行配置
																	//		64Kb 8KB
																	//		可接8个器件,靠地址区分	0-7	高字节为A
																	//		共8192个单元
																	//		0-8191
																	
#define EXTERNAL_MODULE_AT45DB161D_MODE			0					//0:	没有使用AT45DB161D芯片
																	//1:	使用了AT45DB161D芯片,其引脚配置在相应的config文件中进行设置
																	
/*
********************************************************************************
协议层使用配置
********************************************************************************
*/
#define PROTOCOL_MINIUART_UART0_MODE			0					//0:	不针对UART0加载MiniUart
																	//1:	针对UART0加载MiniUart	
																	
#define PROTOCOL_MINIUART_CH432T_UART0_MODE		0					//0:	不针对CH432T_UART0加载MininUart
																	//1:	针对CH432T_UART0加载MiniUart
																	
#define PROTOCOL_MINIUART_CH432T_UART1_MODE		0					//0:	不针对CH432T_UART1加载MininUart	
																	//1:	针对CH432T_UART1加载MiniUart																																									

#endif /* MAIN_H_ */

三、74HC595配置文件的使用

#ifndef HC595_01_CONFIG_H_
#define HC595_01_CONFIG_H_

#define HC595_PORT		PORTC
#define HC595_DDR		DDRC
#define HC595_CLOCK		BIT1
#define HC595_CS		BIT0
#define HC595_MOSI		BIT2

#endif /* HC595_01_CONFIG_H_ */

四、认知74HC595的操作函数和功能宏

#ifndef HC595_H_
#define HC595_H_

//宏定义
#if EXTERNAL_MODULE_HC595_MODE == 1
	#define HC595_SELECT		CLRBIT(HC595_PORT,HC595_CS);SETBIT(HC595_PORT,HC595_CS);CLRBIT(HC595_PORT,HC595_CS)
	#define HC595_UNSELECT		CLRBIT(HC595_PORT,HC595_CS)
	#define HC595_SET_CLOCK 	SETBIT(HC595_PORT,HC595_CLOCK)
	#define HC595_CLR_CLOCK		CLRBIT(HC595_PORT,HC595_CLOCK)
	#define HC595_SET_MOSI		SETBIT(HC595_PORT,HC595_MOSI)
	#define HC595_CLR_MOSI		CLRBIT(HC595_PORT,HC595_MOSI)	
#elif EXTERNAL_MODULE_HC595_MODE == 2
	#define HC595_SELECT		CLRBIT(HC595_PORT_CS,HC595_CS);SETBIT(HC595_PORT_CS,HC595_CS);CLRBIT(HC595_PORT_CS,HC595_CS)
	#define HC595_UNSELECT		CLRBIT(HC595_PORT_CS,HC595_CS)
	#define HC595_SET_CLOCK 	SETBIT(HC595_PORT_CLOCK,HC595_CLOCK)
	#define HC595_CLR_CLOCK		CLRBIT(HC595_PORT_CLOCK,HC595_CLOCK)
	#define HC595_SET_MOSI		SETBIT(HC595_PORT_MOSI,HC595_MOSI)
	#define HC595_CLR_MOSI		CLRBIT(HC595_PORT_MOSI,HC595_MOSI)
#endif

//函数原型声明
void HC595_Init(void);
void HC595_WriteByte(uint8 u8_Byte);

#endif /* HC595_H_ */

五、“0”的字模

六、显示程序

//加入包含文件
#include "../include.h"

//定义系统常量

//定义全局变量

//主程序
int main(void)
{
	//定义局部变量
	
	//目标板初始化,该函数会自动初始化相应的外设文件	
	TARGET_Init();
	
	//初始化全局变量	
		
	//在上电时,执行的相应操作	
			
	//后台主循环
	while(1)
	{
		/*
		**********************************
		在这里完成自己的项目逻辑
		**********************************
		*/	
		HC595_WriteByte(0x80);
		HC595_WriteByte(0xBE);
		HC595_WriteByte(0x80);
		HC595_SELECT;					
		/*
		**********************************
		喂狗语句,大部分工程项目都不应去除
		**********************************
		*/	
		#if INTERNAL_PERIPHERAL_WDT_MODE != 0
			TARGET_WatchDogReset();
		#endif
	}
	return 0;	//永不执行
}

 

 

 

任何问题,只需在此文章的评论处留言即可,我将尽力解答,不要试图采用其它的联系方式,我一概不理会。

原创性文章,转载请注明出处CSDN:http://blog.csdn.net/qingwufeiyang12346。

 

 

 

单片机对1602液晶的控制

博文 来自: Wekic
没有更多推荐了,返回首页