当前位置:文档之家› [PIC单片机] 吴坚鸿单片机程序风格赏析【2】

[PIC单片机] 吴坚鸿单片机程序风格赏析【2】

[PIC单片机] 吴坚鸿单片机程序风格赏析【2】
[PIC单片机] 吴坚鸿单片机程序风格赏析【2】

第十一节:鸿哥单色液晶屏三大类定律(KS0107驱动12864屏)

(1)开场白:

我曾经做过一年的液晶屏工程师,“出家”做自由职业者之后我又在很多项目上应用液晶屏。深圳很多液晶模块公司都是用我帮他们做的测试程序。不管什么品种的单色屏我都能玩得转。谦虚一点说就是,在单色液晶驱动程序这方面,吴坚鸿在全国绝对排名在前三名之内(如果不谦虚地说我就号称第一了,呵呵)。

接下来我要介绍一下我的新发现,单色屏驱动程序的三大类定律。市面上有各种各样的单色屏,什么点阵,段码等等,但是都逃不出我总结的三大类定律。读者只要学会了鸿哥的三大类定律,以后任何单色屏对于你们来说都是浮云。

想要驱动液晶屏,只要知道怎么样在任何一个地方(X轴与Y轴坐标)显示一个基本单位就够了。在单色液晶屏领域,这个显示的基本单位只有三种类型,也就是我总结的三大类定律。

第一大类定律:纵向显示八个点的类型。

这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。而X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。

第二大类定律:横向显示八个点的类型。

这类液晶屏在横向上以八个点(一个字节)为基本单位,因此X坐标数值的最大范围是横向上的点阵数除以八,然后再减去一(因为从零开始)。而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。

第三大类定律:任意位置显示一个点的类型。

这类液晶屏在任意位置上以一个点为基本单位,因此X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。

下面,我以驱动芯片为KS0107的12864液晶屏为例子,来介绍一下第一大类定律:纵向显示八个点的类型。12864液晶屏实际上是由左右两块6464液晶屏合并在一起的,然后通过两根IO口来片选不同的6464液晶屏。因此,我们只要弄懂了一块6464液晶屏的显示方法就够了。6464屏在横向上是64个点,纵向上是64个点,也就是一个正方形的屏。因为它属于第一大类的屏,所以X轴坐标数值的最大范围是64-1=63,而纵向坐标数值的最大范围是(64/8)-1=7.正常的操作思路是这样的,先发送X轴与Y轴的位置数据,确定位置后,就发送一个字节(八个点)的显示数据。这类屏还有一个特征,连续发送显示数据时,在横向(X轴上)的位置数据会自动加一,因此如果在不换行的情况下,只要设定一次位置,就可以从左到右连续发送显示的数据。当换行显示数据时,必须重新设定一下坐标位置。

字节正序与倒序的概念解释:当我们一次在纵向上显示八个点的基本单位时,实际上等于我们发送了一个字节的显示数据,比如0x01,如果是正序的屏,那么从上到下的八个点中,只有第8个点是显示的,其它的是空白,而如果是倒序的屏,则只有第1个点是显示的,其它是空白的。12864这个屏是属于倒序的屏。

取模软件是必须的,读者可以在网上自己下载,资料很多。

(2)功能需求:

在12864屏上显示8X16的字符,16X16的汉字,24X24的汉字。

(3)硬件原理:

液晶屏的VEE接20K可调电阻的左边端口,VO接可调电阻的中间端口,VSS接可调电阻的右边端口,此可调电阻在这里用来调节液晶屏的对比度。模块与背光的电源线接上5V,其它数据线跟单片机的IO口连接上。这个大家都懂。

(4)源码适合的单片机:PIC18f4520,晶振为11.0592MHz。

(5)源代码讲解如下:

#include //包含芯片相关头文件

#define Disp_On 0x3f //液晶模块的寄存器初始化的参数,抄网上的,我也从来没有#define Disp_Off 0x3e //研究过它是什么含义,因为根本没必要知道,直接用就行

#define Col_Add 0x40

#define Page_Add 0xb8

#define Start_Line 0xc0

//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr,凡是数据总线后缀都是_bus

#define Lcd_bus PORTB //液晶的数据总线

#define Bf_sr RB7 //芯片忙检查

#define Mcs_dr LATD6 //左右6464屏的片选

#define Scs_dr LATD7 //左右6464屏的片选

#define Enable_dr LATD5 //类似时钟的数据线

#define Di_dr RC7 //数据与指令的选择线

#define RW_dr RD4 //读与写的选择线

void delay(unsigned int t); //时序延时函数声明

void chk_busy () ; //忙检测,液晶驱动时序的一部分

void write_com(unsigned char cmdcode); //往液晶模块写入指令

void write_data(unsigned char Di_drspdata); //往液晶模块写入数据

void screen_clear(); //清空屏的内容

void zf_display816(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示8X16的字符函数,本节的核心内容

void hz_display1616(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示16X16的汉字函数,本节的核心内容

void hz_display2424(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示24X24的汉字函数,本节的核心内容

void init_lcd(); //初始化液晶模块

//补充说明:吴坚鸿程序风格是这样的,凡是字库内容,如果是字符,则前缀用zf,然后紧//跟着点阵数,接着下划线,最后紧跟显示的字符。如果有重复的,则多加一个序列号标////识。如果是汉字,则前缀用hz,其它的一样。

const unsigned char zf816_v[]=//从取模软件中复制的字库,纵向取模,字节倒序

{

/*-- 文字: V --*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/

0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00, };

const unsigned char zf816_5[]=

{

/*-- 文字: 5 --*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/

0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, };

const unsigned char hz1616_hong[]=

{

/*-- 文字: 鸿--*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/

0x10,0x61,0x86,0x60,0x08,0xF8,0x08,0x00,0xFC,0x0E,0x35,0x04,0x44,0x7C,0x00,0x00, 0x04,0x7C,0x03,0x04,0x04,0x03,0x0A,0x08,0x09,0x09,0x09,0x09,0x49,0x81,0x7F,0x00, };

const unsigned char hz1616_ge[]=

{

/*-- 文字: 哥--*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/

0x00,0x02,0x02,0x7A,0x2A,0x2A,0x2A,0x2A,0x7A,0x02,0x02,0x7E,0x02,0x82,0x00,0x00, 0x01,0x01,0x01,0x3D,0x15,0x15,0x15,0x15,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00, };

const unsigned char hz2424_hong[]=

{

/*-- 文字: 鸿--*/

/*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/

0x00,0x80,0x00,0x04,0x18,0x90,0x40,0x40,0x40,0xC0,0x40,0x60,0x40,0xE0,0x20,0x30,

0xAC,0x24,0x20,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x03,0x06,0xF8,0x07,0x00,0x00, 0x80,0xFF,0x80,0x40,0x00,0x7F,0x40,0x40,0x41,0x49,0x58,0x4F,0xC0,0xE0,0x00,0x00,

0x00,0x00,0x01,0x7F,0x60,0x00,0x01,0x01,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,

0x24,0x22,0x62,0x64,0x3F,0x03,0x00,0x00,

};

const unsigned char hz2424_ge[]=

{

/*-- 文字: 哥--*/

/*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/

0x00,0x00,0x00,0x08,0x08,0x08,0xE8,0x48,0x48,0x48,0x48,0x48,0xE8,0x08,0x08,0x08, 0x08,0xF8,0x08,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xD0,0xD3,0x52, 0x52,0x52,0x52,0x52,0xD3,0x10,0x10,0x10,0x10,0xF7,0x10,0x10,0x08,0x08,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x04,0x04,0x04,0x04,0x04,0x0F,0x00,0x20,0x20, 0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,

};

//主程序

main()

{

ADCON0=0x00;

ADCON1=0x0f;

ADCON2=0x00;

TRISA=0x02;

TRISE=0x00;

TRISC=0x7f;

TRISD=0x0f;

TRISB=0x00;

RBPU=0;

SSPEN=0; //决定RA5作为IO

TRISE2=1;

//补充说明,以上的内容为寄存器配置,每种不同的单片机会有点差异,

//大家不用过度关注以上寄存器的配置,只要知道有这么一回事即可

init_lcd(); //初始化液晶屏

screen_clear ();//清空整屏显示内容

Mcs_dr=1;Scs_dr =0; //左6464屏,正显,16X16的汉字,“鸿哥V5”

hz_display1616(0, 0,hz1616_hong,0);

hz_display1616(16, 0,hz1616_ge,0);

zf_display816(32, 0,zf816_V,0);

zf_display816(40, 0,zf816_5,0);

Mcs_dr =0;Scs_dr =1; //右6464屏,反显,24X24的汉字,“鸿哥V5”

hz_display2424(0, 0,hz2424_hong,1);

hz_display2424(24, 0,hz2424_ge,1);

zf_display816(48, 0,zf816_V,1);

zf_display816(56, 0,zf816_5,1);

while(1)

{

CLRWDT(); //喂看门狗,大家不用过度关注此行

}

}

//------------------时序延时子程序-----------------------------

void delay(unsigned int t)

{

unsigned int i,j;

for(i=0;i

for(j=0;j<10;j++)CLRWDT();

}

//------------------忙闲检查,驱动液晶程序的一部分------------------------------

void chk_busy ()

{

TRISB=0xff;

Lcd_bus=0xff;

Di_dr=0;

RW_dr=1;

delay(0);

Enable_dr=1;

while(Bf_sr==1);

Enable_dr=0;

TRISB=0x00;

}

//------------------写命令到LCD,,驱动液晶程序的一部分------------------------------ void write_com(unsigned char cmdcode)

{

chk_busy ();

Di_dr=0;

RW_dr=0;

Lcd_bus=cmdcode;

delay(0);

Enable_dr=1;

delay(0);

Enable_dr=0;

}

//-------------------写数据到LCD,,驱动液晶程序的一部分----------------------------

void write_data(unsigned char Di_drspdata)

{

chk_busy ();

Di_dr=1;

RW_dr=0;

Lcd_bus=Di_drspdata;

delay(0);

Enable_dr=1;

delay(0);

Enable_dr=0;

}

//*------------------清空屏幕的内容,本节的核心内容---------------*/

void screen_clear ()

{

unsigned char j,i;

Mcs_dr=1;Scs_dr=0; //选择左屏6464

for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.

{

write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行

write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始

for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63

{

write_data(0x00); //都显示空内容,达到清空的目的

}

}

Mcs_dr=0;Scs_dr=1; //选择右屏6464

for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.

{

write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行

write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始

for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//

加一,范围是(0到63),64-1=63

{

write_data(0x00); //都显示空内容,达到清空的目的

}

}

}

//显示8X16的字符函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相对//应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显

void zf_display816(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag)

{

unsigned char j=0,i=0;

for(j=0;j<2;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个8X16字符只占用//两行,每行8个点,两行的高度就是16个点,

{

write_com(Page_Add+pag+j);//换下一行Y轴的坐标

write_com(Col_Add+col); //每次换行都重新设定X轴的坐标,

for(i=0;i<8;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个字符的宽度是8个点,因此范围是(0到7),8-1=7.

{

if(opposite_flag ==1) //反显

{

write_data(~zk [8*j+i]); //发送显示的字节数据,纵向显示八个点,一行8个///点,因此8*j }

else //正显

{

write_data(zk [8*j+i]); //发送显示的字节数据,纵向显示八个点,一行8个点,//因此8*j }

}

}

}

//显示16X16的汉字函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显

void hz_display1616(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag)

{

unsigned char j=0,i=0;

for(j=0;j<2;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个16X16汉字只占//

用两行,每行8个点,两行的高度就是16个点,

{

write_com(Page_Add+pag+j);//换下一行Y轴的坐标

write_com(Col_Add+col); //每次换行都重新设定X轴的坐标,

for(i=0;i<16;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个16X16汉字的宽度是16个点,因此范围是(0到15),16-1=15.

{

if(opposite_flag ==1) //反显

{

write_data(~zk [16*j+i]); //发送显示的字节数据,纵向显示八个点,一行16个///点,因此16*j }

else //正显

{

write_data(zk [16*j+i]); //发送显示的字节数据,纵向显示八个点,一行16个点,//因此16*j

}

}

}

}

//显示24X24的汉字函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显

void hz_display2424(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag)

{

unsigned char j=0,i=0;

for(j=0;j<3;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个24X24汉字只占//用三行,每行8个点,三行的高度就是24个点,

{

write_com(Page_Add+pag+j);//换下一行Y轴的坐标

write_com(Col_Add+col); //每次换行都重新设定X轴的坐标,

for(i=0;i<24;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个24X24汉字的宽度是24个点,因此范围是(0到23),24-1=23.

{

if(opposite_flag ==1) //反显

{

write_data(~zk [24*j+i]); //发送显示的字节数据,纵向显示八个点,一行24///个点,因此24*j }

else //正显

{

write_data(zk [24*j+i]); //发送显示的字节数据,纵向显示八个点,一行24个/////点,因此24*j

}

}

}

}

//*------------------初始化LCD屏--------------------------*/

void init_lcd()

{

Mcs_dr=1; //左6464屏初始化

Scs_dr=0;

delay(100);

write_com(Disp_Off);

write_com(Page_Add+0);

write_com(Start_Line+0);

write_com(Col_Add+0);

write_com(Disp_On);

Mcs_dr=0; //右6464屏初始化

Scs_dr=1;

delay(100);

write_com(Disp_Off);

write_com(Page_Add+0);

write_com(Start_Line+0);

write_com(Col_Add+0);

write_com(Disp_On);

}

(6)小结:

读者要重点弄清楚void screen_clear ,void zf_display816, void hz_display1616, void hz_display2424这四个函数他们之间的联系与规律,即可掌握本节内容的精髓。

12864是由左右两个屏合并起来的,如果想一个汉字左边显示在左屏,右边显示在右屏,也就是跨屏显示的功能,或者如果想显示一副128X64的图像,根据本节的精髓,读者只要在程序上做一些改动处理,应该不难的。

这类液晶屏在纵向上只适合显示点阵数是8倍数的字体,如果不是8倍数的点阵字体,则需要在程序上做特殊处理,这种不是8倍数的字体不实用,同时,我认为跨屏显示的功能也不实用,读者也没必要逞强去尝试。

第十二节:液晶屏第一大类定律--纵向显示八个点(KS0107驱动19264屏)

(1)开场白:

在第十一节中介绍了我的新发现“吴坚鸿单色液晶屏三大类定律”,既然是定律就应该是放之四海而皆准,否则就是我吹牛。为了证明它的真理性与普遍性,这节我将以驱动芯片为KS0107的19264屏为例子。

先补一下第十一节的基本知识。想要驱动液晶屏,只要知道怎么样在任何一个地方(X轴与Y轴坐标)显示一个基本单位就够了。在单色液晶屏领域,这个显示的基本单位只有三种类型,也就是我总结的三大类定律。

第一大类定律:纵向显示八个点的类型。

这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。而X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。

第二大类定律:横向显示八个点的类型。

这类液晶屏在横向上以八个点(一个字节)为基本单位,因此X坐标数值的最大范围是横向上的点阵数除以八,然后再减去一(因为从零开始)。而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。

第三大类定律:任意位置显示一个点的类型。

这类液晶屏在任意位置上以一个点为基本单位,因此X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。而Y坐标数值的最大范围就直接是纵向上的点阵数减去一(因为从零开始)。

下面,我以驱动芯片为KS0107的19264液晶屏为例子,来介绍一下第一大类定律:纵向显示八个点的类型。19264液晶屏实际上是由左中右三块6464液晶屏合并在一起的,然后通过三根IO口来片选不同的6464液晶屏。因此,我们只要弄懂了一块6464液晶屏的显示方法就够了。6464屏在横向上是64个点,纵向上是64个点,也就是一个正方形的屏。因为它属于第一大类的屏,所以X轴坐标数值的最大范围是64-1=63,而纵向坐标数值的最大范围是(64/8)-1=7.正常的操作思路是这样的,先发送Y轴与X轴的位置数据,确定位置后,就发送一个字节(八个点)的显示数据。这类屏还有一个特征,连续发送显示数据时,在横向(X轴上)的位置数据会自动加一,因此如果在不换行的情况下,只要设定一次位置,就可以从左到右连续发送显示的数据。当换行显示数据时,必须重新设定一下坐标位置。

字节正序与倒序的概念解释:当我们一次在纵向上显示八个点的基本单位时,实际上等于我们发送了一个字节的显示数据,比如0x01,如果是正序的屏,那么从上到下的八个点中,只有第8个点是显示的,其它的是空白,而如果是倒序的屏,则只有第1个点是显示的,其它是空白的。19264这个屏是属于倒序的屏。

取模软件是必须的,读者可以在网上自己下载,资料很多。

(2)功能需求:

在19264屏上的左边,中间,右边分别显示8X16的字符,16X16的汉字,24X24的汉字。

(3)硬件原理:

液晶屏的VEE接20K可调电阻的左边端口,VO接可调电阻的中间端口,可调电阻的右边端口接电源负极,此可调电阻在这里用来调节液晶屏的对比度。模块与背光的电源线接上5V,其它数据线跟单片机的IO口连接上。这个大家都懂。

(4)源码适合的单片机:PIC18f4520,晶振为11.0592MHz。

(5)源代码讲解如下:

#include //包含芯片相关头文件

#define Disp_On 0x3f //液晶模块的寄存器初始化的参数,抄网上的,我也从来没有#define Disp_Off 0x3e //研究过它是什么含义,因为根本没必要知道,直接用就行

#define Col_Add 0x40

#define Page_Add 0xb8

#define Start_Line 0xc0

//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr,凡是数据总线后缀都是_bus

#define Lcd_bus PORTB //液晶的数据总线

#define Bf_sr RB7 //芯片忙检查

#define Ccs_dr LATD5 //左6464屏的片选

#define Mcs_dr LATD6 //中6464屏的片选

#define Scs_dr LATD7 //右6464屏的片选

#define Enable_dr LATD5 //类似时钟的数据线

#define Di_dr RC7 //数据与指令的选择线

#define RW_dr RD4 //读与写的选择线

void delay(unsigned int t); //时序延时函数声明

void chk_busy () ; //忙检测,液晶驱动时序的一部分

void write_com(unsigned char cmdcode); //往液晶模块写入指令

void write_data(unsigned char Di_drspdata); //往液晶模块写入数据

void screen_clear(); //清空屏的内容

void zf_display816(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示8X16的字符函数,本节的核心内容

void hz_display1616(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示16X16的汉字函数,本节的核心内容

void hz_display2424(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //显示24X24的汉字函数,本节的核心内容

void init_lcd(); //初始化液晶模块

//补充说明:吴坚鸿程序风格是这样的,凡是字库内容,如果是字符,则前缀用zf,然后紧//跟着点阵数,接着下划线,最后紧跟显示的字符。如果有重复的,则多加一个序列号标////识。如果是汉字,则前缀用hz,其它的一样。

const unsigned char zf816_v[]=//从取模软件中复制的字库,纵向取模,字节倒序

{

/*-- 文字: V --*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/

0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,

};

const unsigned char zf816_5[]=

{

/*-- 文字: 5 --*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/

0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,

};

const unsigned char hz1616_hong[]=

{

/*-- 文字: 鸿--*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/

0x10,0x61,0x86,0x60,0x08,0xF8,0x08,0x00,0xFC,0x0E,0x35,0x04,0x44,0x7C,0x00,0x00, 0x04,0x7C,0x03,0x04,0x04,0x03,0x0A,0x08,0x09,0x09,0x09,0x09,0x49,0x81,0x7F,0x00, };

const unsigned char hz1616_ge[]=

{

/*-- 文字: 哥--*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/

0x00,0x02,0x02,0x7A,0x2A,0x2A,0x2A,0x2A,0x7A,0x02,0x02,0x7E,0x02,0x82,0x00,0x00, 0x01,0x01,0x01,0x3D,0x15,0x15,0x15,0x15,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00, };

const unsigned char hz2424_hong[]=

{

/*-- 文字: 鸿--*/

/*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/

0x00,0x80,0x00,0x04,0x18,0x90,0x40,0x40,0x40,0xC0,0x40,0x60,0x40,0xE0,0x20,0x30,

0xAC,0x24,0x20,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x03,0x06,0xF8,0x07,0x00,0x00, 0x80,0xFF,0x80,0x40,0x00,0x7F,0x40,0x40,0x41,0x49,0x58,0x4F,0xC0,0xE0,0x00,0x00,

0x00,0x00,0x01,0x7F,0x60,0x00,0x01,0x01,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,

0x24,0x22,0x62,0x64,0x3F,0x03,0x00,0x00,

};

const unsigned char hz2424_ge[]=

{

/*-- 文字: 哥--*/

/*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/

0x00,0x00,0x00,0x08,0x08,0x08,0xE8,0x48,0x48,0x48,0x48,0x48,0xE8,0x08,0x08,0x08,

0x08,0xF8,0x08,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xD0,0xD3,0x52, 0x52,0x52,0x52,0x52,0xD3,0x10,0x10,0x10,0x10,0xF7,0x10,0x10,0x08,0x08,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x04,0x04,0x04,0x04,0x04,0x0F,0x00,0x20,0x20,

0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,

};

//主程序

main()

{

ADCON0=0x00;

ADCON1=0x0f;

ADCON2=0x00;

TRISA=0x02;

TRISE=0x00;

TRISC=0x7f;

TRISD=0x0f;

TRISB=0x00;

RBPU=0;

SSPEN=0; //决定RA5作为IO

TRISE2=1;

//补充说明,以上的内容为寄存器配置,每种不同的单片机会有点差异,

//大家不用过度关注以上寄存器的配置,只要知道有这么一回事即可

init_lcd(); //初始化液晶屏

screen_clear ();//清空整屏显示内容

Ccs_dr=0;Mcs_dr=1;Scs_dr =1; //左6464屏,正显,16X16的汉字,“鸿哥V5”hz_display1616(0, 0,hz1616_hong,0);

hz_display1616(16, 0,hz1616_ge,0);

zf_display816(32, 0,zf816_V,0);

zf_display816(40, 0,zf816_5,0);

Ccs_dr=1;Mcs_dr =0;Scs_dr =1; //中6464屏,反显,24X24的汉字,“鸿哥V5”hz_display2424(0, 0,hz2424_hong,1);

hz_display2424(24, 0,hz2424_ge,1);

zf_display816(48, 0,zf816_V,1);

zf_display816(56, 0,zf816_5,1);

Ccs_dr=1;Mcs_dr =1;Scs_dr =0; //右6464屏,正显,24X24的汉字,“鸿哥V5”hz_display2424(0, 0,hz2424_hong,0);

hz_display2424(24, 0,hz2424_ge,0);

zf_display816(48, 0,zf816_V,0);

zf_display816(56, 0,zf816_5,0);

while(1)

{

CLRWDT(); //喂看门狗,大家不用过度关注此行

}

}

//------------------时序延时子程序-----------------------------

void delay(unsigned int t)

{

unsigned int i,j;

for(i=0;i

for(j=0;j<10;j++)CLRWDT();

}

//------------------忙闲检查,驱动液晶程序的一部分------------------------------

void chk_busy ()

{

TRISB=0xff;

Lcd_bus=0xff;

Di_dr=0;

RW_dr=1;

delay(0);

Enable_dr=1;

while(Bf_sr==1);

Enable_dr=0;

TRISB=0x00;

}

//------------------写命令到LCD,,驱动液晶程序的一部分------------------------------

void write_com(unsigned char cmdcode)

{

chk_busy ();

Di_dr=0;

RW_dr=0;

Lcd_bus=cmdcode;

delay(0);

Enable_dr=1;

delay(0);

Enable_dr=0;

}

//-------------------写数据到LCD,,驱动液晶程序的一部分----------------------------

void write_data(unsigned char Di_drspdata)

{

chk_busy ();

Di_dr=1;

RW_dr=0;

Lcd_bus=Di_drspdata;

delay(0);

Enable_dr=1;

delay(0);

Enable_dr=0;

}

//*------------------清空屏幕的内容,本节的核心内容---------------*/

void screen_clear ()

{

unsigned char j,i;

Ccs_dr=0;Mcs_dr=1;Scs_dr=1; //选择左屏6464

for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.

{

write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行

write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始

for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63

{

write_data(0x00); //都显示空内容,达到清空的目的

}

}

Ccs_dr=1;Mcs_dr=0;Scs_dr=1; //选择中屏6464

for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.

{

write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行

write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始

for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63

{

write_data(0x00); //都显示空内容,达到清空的目的

}

}

Ccs_dr=1;Mcs_dr=1;Scs_dr=0; //选择右屏6464

for(j =0; j <8; j ++) //此处的j代表Y轴的坐标,范围是(0到7),(64/8)-1=7.

{

write_com(Page_Add+ j); //设定Y轴的起始位置,切换到下一行

write_com(Col_Add+0); //设定X轴的起始位置,每次换行都从0开始

for(i=0; i <64; i ++) //此处i代表X轴,每发送一个显示数据,X轴内部的位置会自动//加一,范围是(0到63),64-1=63

{

write_data(0x00); //都显示空内容,达到清空的目的

}

}

}

//显示8X16的字符函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相对//应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显

void zf_display816(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag)

{

unsigned char j=0,i=0;

for(j=0;j<2;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个8X16字符只占用//两行,每行8个点,两行的高度就是16个点,

{

write_com(Page_Add+pag+j);//换下一行Y轴的坐标

write_com(Col_Add+col); //每次换行都重新设定X轴的坐标,

for(i=0;i<8;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个字符的宽度是8个点,因此范围是(0到7),8-1=7.

{

if(opposite_flag ==1) //反显

{

write_data(~zk [8*j+i]); //发送显示的字节数据,纵向显示八个点,一行8个///点,因此8*j }

else //正显

{

write_data(zk [8*j+i]); //发送显示的字节数据,纵向显示八个点,一行8个点,//因此8*j }

}

}

}

//显示16X16的汉字函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显

void hz_display1616(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag)

{

unsigned char j=0,i=0;

for(j=0;j<2;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个16X16汉字只占//用两行,每行8个点,两行的高度就是16个点,

{

write_com(Page_Add+pag+j);//换下一行Y轴的坐标

write_com(Col_Add+col); //每次换行都重新设定X轴的坐标,

for(i=0;i<16;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个16X16汉字的宽度是16个点,因此范围是(0到15),16-1=15.

{

if(opposite_flag ==1) //反显

{

write_data(~zk [16*j+i]); //发送显示的字节数据,纵向显示八个点,一行16个///点,因此16*j }

else //正显

{

write_data(zk [16*j+i]); //发送显示的字节数据,纵向显示八个点,一行16个点,//因此16*j

}

}

}

}

//显示24X24的汉字函数,本节的核心内容。col代表X轴,pag代表Y轴,zk代表显示相//对应的字库,opposite_flag代表是否反显,0表示正常显示,1表示反显

void hz_display2424(unsigned char col, unsigned char pag,const unsigned char *zk,unsigned char opposite_flag)

{

unsigned char j=0,i=0;

for(j=0;j<3;j++) //此处j代表Y轴的数据,也就是显示第几行了,一个24X24汉字只占//用三行,每行8个点,三行的高度就是24个点,

{

write_com(Page_Add+pag+j);//换下一行Y轴的坐标

write_com(Col_Add+col); //每次换行都重新设定X轴的坐标,

for(i=0;i<24;i++) //此处i代表X轴的数据,每发送一个显示数据,X轴位置会自动加/////一,因为一个24X24汉字的宽度是24个点,因此范围是(0到23),24-1=23.

{

if(opposite_flag ==1) //反显

{

write_data(~zk [24*j+i]); //发送显示的字节数据,纵向显示八个点,一行24///个点,因此24*j

}

else //正显

{

write_data(zk [24*j+i]); //发送显示的字节数据,纵向显示八个点,一行24个/////点,因此24*j

}

}

}

}

//*------------------初始化LCD屏--------------------------*/

void init_lcd()

{

Ccs_dr=0;

Mcs_dr=1; //左6464屏初始化

Scs_dr=1;

delay(100);

write_com(Disp_Off);

write_com(Page_Add+0);

write_com(Start_Line+0);

write_com(Col_Add+0);

write_com(Disp_On);

Ccs_dr=1;

Mcs_dr=0; //中6464屏初始化

Scs_dr=1;

delay(100);

write_com(Disp_Off);

write_com(Page_Add+0);

write_com(Start_Line+0);

write_com(Col_Add+0);

write_com(Disp_On);

Ccs_dr=1;

Mcs_dr=1; //右6464屏初始化

Scs_dr=0;

delay(100);

write_com(Disp_Off);

write_com(Page_Add+0);

write_com(Start_Line+0);

write_com(Col_Add+0);

write_com(Disp_On);

}

(6)小结:

读者要重点弄清楚void screen_clear ,void zf_display816, void hz_display1616, void hz_display2424这四个函数他们之间的联系与规律,即可掌握本节内容的精髓。

根据第一大类定律的原理,在第十一节12864程序的基础上略做修改,就可改成本

节19264屏的驱动程序,非常方便

第十三节:液晶屏第一大类定律--纵向显示八个点(SED1520驱动12232屏)

第一大类定律:纵向显示八个点的类型。

这类液晶屏在纵向上以八个点(一个字节)为基本单位,因此Y坐标数值的最大范围是纵向上的点阵数除以八,然后再减去一(因为从零开始)。而X坐标数值的最大范围就直接是横向上的点阵数减去一(因为从零开始)。

(1)开场白:

这节我以驱动芯片为SED1520的12232液晶屏为例子,来继续深入了解第一大类定律:纵向显示八个点的类型。12232液晶屏实际上是由左右两块6132的液晶屏合并在一起的,跟前面提到的驱动芯片为KS0107的12864屏稍微有点不一样,它不是由两根IO口来片选不同的屏,而是通过两根不同的时钟线来区分不同的屏。因此,我们只要弄懂了一块6132液晶屏的显示方法就够了。6132屏在横向上是61个点,纵向上是32个点,也就是一个长方形的屏。因为它属于第一大类的屏,所以X轴坐标数值的最大范围是61-1=60,而纵向坐标数值的最大范围是(32/8)-1=3.正常的操作思路是这样的,先发送Y轴与X轴的位置数据,确定位置后,再发送一个字节(八个点)的显示数据。这类屏跟之前介绍KS0107驱动12864的屏稍微有点不一样,每发送一次显示数据时,都要先重新设置一下Y与X轴的位置,X地址不会自动加一。

字节正序与倒序的概念解释:当我们一次在纵向上显示八个点的基本单位时,实际上等于我们发送了一个字节的显示数据,比如0x01,如果是正序的屏,那么从上到下的八个点中,只有第8个点是显示的,其它的是空白,而如果是倒序的屏,则只有第1个点是显示的,其它是空白的。12232这个屏是属于倒序的屏。

取模软件是必须的,读者可以在网上自己下载,资料很多。

(2)功能需求:

在12232屏上的左屏和右屏分别显示8X16的字符,16X16的汉字,24X24的汉字。(3)硬件原理:

这类屏跟之前介绍KS0107驱动12864的屏稍微有点不一样,它没有的VEE这个端口。20K可调电阻的左边端口直接悬空,VO接可调电阻的中间端口,可调电阻的右边端口接电源负极,此可调电阻在这里用来调节液晶屏的对比度。模块的复位引脚直接用一个15K的电阻跟一个104电容搭成上电低电平硬件复位电路,省一个IO口,也就是此IO口接一个15K的上拉电阻,然后对地再接一个104电容。模块与背光的电源线接上5V,其它数据线跟单片机的IO口连接上。这个大家都懂。

(4)源码适合的单片机:PIC18f4520,晶振为11.0592MHz。

(5)源代码讲解如下:

#include //包含芯片相关头文件

//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr,凡是数据总线后缀都是_bus

#define E1_dr LATD4

#define E2_dr LATD5

#define RW_dr LATD6

#define RS_dr LATD7

#define LcmDataBus PORTB

void delay(unsigned int t); //时序延时函数声明

void chk_busy_left () ; //左屏忙检测,液晶驱动时序的一部分

void chk_busy_right () ; //左屏忙检测,液晶驱动时序的一部分

void write_com_left(unsigned char cmdcode); //往左液晶模块写入指令

void write_com_right(unsigned char cmdcode); //往右液晶模块写入指令

void write_data_left(unsigned char Di_drspdata); //往左液晶模块写入数据

void write_data_right(unsigned char Di_drspdata); //往右液晶模块写入数据

void screen_clear(); //清空屏的内容

void zf_display816_left(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //左显示8X16的字符函数,本节的核心内容

void zf_display816_right(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //右显示8X16的字符函数,本节的核心内容

void hz_display1616_left(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //左屏,显示16X16的汉字函数,本节的核心内容

void hz_display1616_right(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //右屏,显示16X16的汉字函数,本节的核心内容

void hz_display2424_left(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //左屏,显示24X24的汉字函数,本节的核心内容

void hz_display2424_right(unsigned char col, unsigned char pag,const unsigned char * zk,unsigned char opposite_flag); //右屏,显示24X24的汉字函数,本节的核心内容

void init_lcd(); //初始化液晶模块

//补充说明:吴坚鸿程序风格是这样的,凡是字库内容,如果是字符,则前缀用zf,然后紧//跟着点阵数,接着下划线,最后紧跟显示的字符。如果有重复的,则多加一个序列号标////识。如果是汉字,则前缀用hz,其它的一样。

const unsigned char zf816_V[]=//从取模软件中复制的字库,纵向取模,字节倒序

{

/*-- 文字: V --*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/

0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,

};

const unsigned char zf816_5[]=

{

/*-- 文字: 5 --*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/

0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, };

const unsigned char hz1616_hong[]=

{

/*-- 文字: 鸿--*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/

0x10,0x61,0x86,0x60,0x08,0xF8,0x08,0x00,0xFC,0x0E,0x35,0x04,0x44,0x7C,0x00,0x00, 0x04,0x7C,0x03,0x04,0x04,0x03,0x0A,0x08,0x09,0x09,0x09,0x09,0x49,0x81,0x7F,0x00, };

const unsigned char hz1616_ge[]=

{

/*-- 文字: 哥--*/

/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/

0x00,0x02,0x02,0x7A,0x2A,0x2A,0x2A,0x2A,0x7A,0x02,0x02,0x7E,0x02,0x82,0x00,0x00, 0x01,0x01,0x01,0x3D,0x15,0x15,0x15,0x15,0x3D,0x41,0x81,0x7F,0x01,0x01,0x01,0x00, };

const unsigned char hz2424_hong[]=

{

/*-- 文字: 鸿--*/

/*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/

0x00,0x80,0x00,0x04,0x18,0x90,0x40,0x40,0x40,0xC0,0x40,0x60,0x40,0xE0,0x20,0x30,

0xAC,0x24,0x20,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x03,0x06,0xF8,0x07,0x00,0x00, 0x80,0xFF,0x80,0x40,0x00,0x7F,0x40,0x40,0x41,0x49,0x58,0x4F,0xC0,0xE0,0x00,0x00,

0x00,0x00,0x01,0x7F,0x60,0x00,0x01,0x01,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,

0x24,0x22,0x62,0x64,0x3F,0x03,0x00,0x00,

};

const unsigned char hz2424_ge[]=

{

/*-- 文字: 哥--*/

/*-- 宋体18; 此字体下对应的点阵为:宽x高=24x24 --*/

0x00,0x00,0x00,0x08,0x08,0x08,0xE8,0x48,0x48,0x48,0x48,0x48,0xE8,0x08,0x08,0x08,

0x08,0xF8,0x08,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xD0,0xD3,0x52, 0x52,0x52,0x52,0x52,0xD3,0x10,0x10,0x10,0x10,0xF7,0x10,0x10,0x08,0x08,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x04,0x04,0x04,0x04,0x04,0x0F,0x00,0x20,0x20,

0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,

51单片机实验程序

3 3 3 用查表方式编写y=x1 +x2 +x3 。(x 为0~9 的整数) #include void main() { int code a[10]={0,1,8,27,64,125,216,343,512,729}; //将0~9 对应的每位数字的三次方的值存入code中,code为程序存储器,当所存的值在0~255 或-128~+127 之间的话就用char ,而现在的值明显超过这个范围,用int 较合适。int 的范围是0~65535 或-32768~32767 。 int y,x1,x2,x3; //此处定义根据习惯,也可写成char x1,x2,x3 但是变量y 一定要用int 来定义。 x1=2; x2=4; x3=9; //x1,x2,x3 三个的值是自定的,只要是0~9 当中的数值皆可,也可重复。 y=a[x1]+a[x2]+a[x3]; while(1); //单片机的程序不能停,这步就相当于无限循环的指令,循环的内容为空白。 } //结果的查询在Keilvision 软件内部,在仿真界面点击右下角(一般初始位置是右下角)的watch 的框架内双击“double-click or F2 to add”文字输入y 后按回车,右侧会显示其16 进制数值如0x34,鼠标右键该十六进制,选择第一行的decimal,可查看对应的10 进制数。 1、有10 个8 位二进制数据,要求对这些数据进行奇偶校验,凡是满足偶校验的 数据(1 的个数为偶数)都要存到内RAM50H 开始的数据区中。试编写有关程序。 #include void main() { int a[10]={0,1,5,20,24,54,64,88,101,105}; // 将所要处理的值存入RAM 中,这些可以根据个人随意设定,但建议不要超过0~255 的范围。 char i; // 定义一个变量 char *q=0x50; // 定义一个指针*q 指向内部0x50 这个地址。 for(i=9;i>=0;i--) //9~0 循环,共十次,也可以用for(i=0;i<10;i++) { ACC=a[i]; //将a[i] 的值赋给累加器ACC if (P==0) //PSW0 位上的奇偶校验位,如果累加器ACC 内数值1 的个数为偶数那么P 为0,若为奇数,P 为1。这里的P 是大写的。 { *q=a[i]; q++; // 每赋一个值,指针挪一个位置指向下一个。 } } while(1); //同实验一,程序不能停。 }

单片机实验答案

前言 由于单片机具有高可靠性、超小型、低价格、容易产品化等特点,在仪器仪表智能化、实时工业控制、实时数据采集、智能终端、通信设备、导航系统、家用电器等控制应用领域,具有十分广泛的用途。目前在国内单片机应用中,MCS-51系列单片机仍然是一种主流单片机。为配合《单片机应用技术》课程的教学,使学生尽快了解、掌握89C51单片机的使用,特编写了这本上机指导书(基础篇)。 《单片机》是一门实践性很强的课程,提高教学质量的一个重要环节是上机实习和训练,无论是学习汇编语言程序设计,还是学习接口电路和外设与计算机的连接,或者软硬兼施地研制单片机应用系统,不通过加强动手是不能获得预期效果的。本实验指导书提供了9个实验的指导性材料,实验还有一些思考题,可以根据课时的安排和教学要求进行取舍。为了达到某些实验的目的,书中提供的参考程序与实际应用中的程序会有些差别,所以不一定是最优的。 由于时间紧迫,加上编者学识有限,如有不妥之处,欢迎读者批评指正。 编者

实验须知 1. 实验前必须阅读教科书的有关部分和本实验指导书,了解实验目的、内容、步骤,做好实验前的准备工作,编写好实验中要求自编或修改的程序;完成实验前要求完成的准备工作后方可以上机实验,否则不得上机操作。 2. 各种电源的电压和极性不能接错,严禁带电接线和接插元器件。通电前须经过指导教师检查认可后方能通电。 3. 不准随意拨弄各种与实验无关的旋钮和开关,凡与本次实验无关的任何设备都禁止动用和摸弄,注意安全。 4. 严禁用手触摸实验系统印制电路板和元器件的引脚,防止静电击穿芯片。 5. 实验中若损坏仪器或元器件,应及时向指导教师报告,听候处理。 6. 在实验室内保持安静和卫生,不得随意走动和喧哗,集中精力完成实验。 7. 实验完成后,关掉电源,及时整理实验台桌面,保持环境整洁。 8. 按规定认真完成实验报告,对实验中出现的现象进行分析,在规定的时间内交上实验报告。 9. 凡实验或实验报告未能按规定完成的学生,不能参加本课程的考试或考查。

单片机实验指导书——带答案

《单片机原理及应用》 实验指导书 姓名: 学号: 专业班级: 所在学院:成人教育学院 2012年5月日 单片机实验指导书

目录 实验一系统认识实验 (2) 实验二程序调试 (4) 实验三外部中断实验 (6) 实验四串口实验 (8) 实验一系统认识实验 一、实验目的 1.掌握SICElab-G2200实验/仿真系统的结构与使用方法; 2.熟悉单片机系统开发软件WAVE6000。

二、实验设备 1.G2200/2100 实验平台 1 台 2.仿真器/ 仿真板 1 台 3.连线若干根 4.计算机 1 台 三、实验内容 P1端口接发光二极管,加1点亮。 四、连线方案: 实验箱 内部已 连好 五、实验步骤 1.连接Lab51CPU板。(已由实验师连好) 2.仿真器与实验平台的连接 将Lab51板的DC34芯插座与G6W仿真器上的DC34插座用扁平电缆连接起来。(已由实验师连好) 3.仿真器与计算机的连接 用随机配带的串口通讯电缆,将仿真器与计算机连接起来,串口1、串口2均可。 特别注意:在仿真器与计算机连接串口电缆时,两台机器必须都断电,否则易损坏计算机和仿真器。 4.实验连线 按连线方案,用随机配带的实验连线插入孔后,轻轻转动一下锁紧插头,保证良好接触。拆线时,应先回转一下,不要硬拨,以免损坏线路板。不管是拆线还是插线,都应在断电的情况下进行。实验中“连线方案”的粗线即为需用户动手接连的线。 5.检查接线是否有误,确信没有接错后,接上电源,打开电源开关。 6.在计算机上打开“WAVE6000集成调试环境”,界面如下图所示: 7.建立新程序(如果程序已编好,直接跳到第9步) 选择菜单[文件 | 新建文件]功能。 出现一个文件名为NONAME1的源程序窗口,在此窗口中输入以下程序 ORG 0 MOV P1,#0 ;熄灭发光二极管 LOOP: INC P1 CALL Delay SJMP LOOP Delay: MOV R2,#3 ;延时程序 MOV R1,#0

单片机-实验二-分支程序设计实验

实验二实验报告 ·

将00-99的十进制数据转换成二进制进行开关量的输入,L0灯亮 将100的十进制转换为01100010的二进制开关量进行输入,L1灯亮

将101-127的十进制转换为二进制进行开关量的输入,L2灯亮 完整的接线图

实验操作 1、正确连接实验板子和电脑,将点源接入,数据线连接到电脑的USB接口,在电脑端运行 软件,取消勾选模拟器,按照实验装置的名称正确的选择响应的系统。 2、在软件内部按照输入分支程序结构。 3、打开点源开关。 4、调整输入的各个断口的开关量,着重关注在二进制数01100010附近的变化. 5、整理实验器材。 思考题1 写出分支程序设计的要点 分支结构也成为选择结构。在程序中每个分支均为一个程序段。为分支需要,程序设计时不要忘记给程序段的起始地址赋予一个地址标号,以供选择分支使用。 这次实验使用的是一个多分支程序结构,可以通过一系列的JC\JNC\JB\JNB的判断,进行逐级分支。并且可以使用CJNE进行实现。 80C51中没有专门的多分支转移指令,可以使用的变址转移指令“JMP @A+DPTR”,但是这样的指令需要数据表格配合。 思考题2 8051单片机有几个并行口,写出各并行口的特点 8051单片机有4个并行I/O口,分别为P0\P1\P2\P3,以实现数据的并行输入与输出。 这4个并行口均是8为双向口线,各占8个引脚,在P3口线上有着引脚复用,均有第二功能信号,这些第二功能信号都是重要的控制信号,在实际使用中总是先按需要优先选用第二功能,剩下的不用的再当作口线使用。 并行可以有效的提高单片机的工作效率。 思考题3 实验中遇到的苦难 在这个实验中和实验一显著不同的是我们需要重新认识硬件与软件的配合,一些数据线的链接,点源的通断都是我们学习的要点,我们也第一次接触到了输入口和输出口相互之间的区别。 这个实验我们一定要将十进制的思维转换过来转换为二进制的思维,在机器语言中只有开关量的通断,而这个题目也是很好的应用了开关量的通断完成了这个实验。 学会了分支判断方式的编程

单片机实验二

单片机实验报告(二) 姓名:赵苑珺 学号:090250129

实验三程序设计(二) 一、实验目的 1、了解汇编语言程序设计与调试的过程; 2、掌握循环程序、查表程序和子程序的特点及设计。 二、实验内容 1、循环程序的设计、输入、调试和运行; 2、查表程序的设计、输入、调试和运行; 3、子程序的设计、输入、调试和运行。 三、实验步骤 1、排序程序:将N 个数从小到大排列起来。 设R0 的内容为数据区的首地址,R7 的内容为数据的字节数。参考程序为:MOV R0,#30H ;将序列首地址存入R0中 MOV R7,#10 ;将序列长度存入R7中 SS: MOV A,R7 MOV R2,A MOV 60H,R0 ;将序列首地址存入60H NN: DEC R2 ;循环程序,控制排序次数 MOV A,R2 MOV R3,A MOV R0,60H L1: MOV A,@R0 ;将序列第一个数存入A中 INC R0 ;R0加1,指向第二个位置 CLR C ;清除进位标志位C,为比较两数大小做准备 SUBB A,@R0 ;第一个数减去第二个数 JC MM ;判断C的状态,1(代表数1小于数2)跳至MM,0(代表数 1大于数2)继续执行 MOV A,@R0 ;将第二个数存入累加器A中 DEC R0 ;R0指向第一个位置 XCH A,@R0 ;将A中的数(数1)与R0指向的数(数2)交换 INC R0 ;R0减一,指向位置一 MOV @R0,A ;将A中的数2存到位置一内 SETB F0 ;置位用户标志位,表示有交换 MM: DJNZ R3,L1 ;R3减一不为零则跳至L1,否则继续执行程序 MOV A,R2 CJNE R2,#01H,L2 ;判断R2中的数是否已经减为1,是跳至JJ,否跳至L2 SJMP JJ L2: JB F0,NN ;判断F0状态,若为1(有交换)则跳至NN,否则继续进行JJ: MOV R0,60H ;将序列首地址存入R0 END

北京交通大学单片机实验程序报告

单片机实验程序

实验二8155并行I/O口扩展和动态扫描程序编制 1.实验目的 (1)掌握8155并行I/O芯片扩展和使用方法 (2)掌握数码管动态扫描汇编语言的编制方法 2.预习要点 (1)8155芯片基础知识 (2)51单片机的总线时序、地址译码的原理 (3)数码管动态扫描显示方法 3.实验设备 计算机、单片机实验箱。 4.实验内容 基本要求: 通过实验板的上的8155(U16)显示电路(在电路板上已经固定连接字形和字位控制线的8155部分),并通过跳线确定8155的地址,在8个LED数码管上依次动态显示数字1~8。 扩展要求: 假定30H~33H的存储单元内容为4个字节16进制数,请依序将他们显示在8个LED数码管上 根据程序要求做如下程序流程图: 主程序流程图:

显示子程序流程框图: 基本要求编程如下: ORG 0000H

AJMP MAIN ORG 0050H MAIN: MOV SP,#60H ;压栈 MOV DPTR, #4100H MOV A,#0FH ;方式控制字0FH送A MOVX @DPTR, A ;8155初始化 MOV 70H,#01H ;设置显示缓冲区 MOV 71H,#02H MOV 72H,#03H MOV 73H,#04H MOV 74H,#05H MOV 75H,#06H MOV 76H,#07H MOV 77H,#08H LOOP: ACALL DISPLAY ;循环调用显示子程序AJMP LOOP DISPLAY: MOV R0,#70H ;显示缓冲区首地址送R0 MOV R3,#0FEH ;字位控制初值送R3

单片机实验程序设计

实验一LED流水灯 一、实验目的 制作一个流水灯,编写程序来控制发光二极管由上至下的反复循环流水点亮,每次点亮一个发光二极管。 二、程序设计 #include #include sbit LED = P1^0; void delay() { unsigned int i,j; for(i=120;i>0;i++) for(j=120;j>0;j++); } void main() { unsigned char i; LED = 0; while(1) { for(i=0;i<8;i++) { LED=0xfe; delay( ); LED = _crol_(LED,1); P1 = LED; } LED=0X01; for(i=0;i<8;i++) { delay( ); LED = _cror_(LED,1); P1 = LED; } } }

实验二按键扫描 一、实验目的 使用单片机片内的I/O口来进行开关状态的检测。当开关打开时,I/O引脚为高电平,当开关闭合时,I/O引脚为低电平。编写一个程序,控制流水灯,开关闭合,对应的发光二极管点亮。 二、程序设计 #include #include #define GPIO_LED P1 sbit K1=P3^5; sbit K2=P3^4; void Delay10ms( ); void main(void) { unsigned int i,j,l; j=0xfe; while(1) { GPIO_LED=j; if (K1==0) { Delay10ms( ); if (K1==0) { j=_cror_(j,1); while((i<50)&&(K1==0)) { Delay10ms( ); i++; } i=0; } } if (K2==0) { Delay10ms( ); if (K2==0) { l=0xff; GPIO_LED=~l;

单片机实验二 中断程序

实验二:中断 一、实验要求 实验目的:学会使用uVision 4和Proteus软件进行单片机汇编语言和C语言程序设计与开发;了解和掌握MCS-51单片机的中段组成、中断控制工作原理、中断处理过程、外部中断的中断触发方式,掌握中断功能的编程方法。 实验内容:单片机的P1.0引脚接LED指示灯D0;P3.2接按键开关K作为中断源可每次案件都会触发INT0中断;在INT0中断服务程序中将P1.0端口的信号取反,是LED指示灯D0在点亮和熄灭两种状态间切换,产生LED指示灯由按键K控制的效果。 二、实验原理 中断服务程序的设计主要包括两部分:初始化程序和中断服务程序。 初始化程序主要完成为响应中断而进行的初始化工作。这些工作主要有:中断源的设置、中断服务程序中有关工作单元的初始化和中断控制的设置等。 中断源的设置与硬件设计有关,各中断请求标志由存储器TCON和SCON中有关标志位来表示,所以中断源的初试化工作主等要有初试化各中断请求标志和请求外部中断信号的类型。 中断服务程序通常由现场保护、总段处理和恢复现场三个部分组成。MSC-51单片机所做的断电保护工作是很有限的,只保护了一个端点地址。所以如果在主程序中用到如A、PSW、DPTR和R0~R7等寄存器,而在中观程序中又要用他们,这就要保证回到主程序后,这些寄存器还要回复到未执行中断前的内容。在运行中断处理程序前,将中断处理程序中用到的寄存器内容先保存起来,这就是所谓的“现场保护”。好糊A、PSW、DPTR等内容,通常可用压入堆栈命令(PUSH)指令,对保护R0~R7等寄存器可用改变工作寄存器区的方法。 中断处理结束后,将中断处理程序中用到的寄存器内容恢复到中断前的内容,即“恢复现场”。恢复现场要与保护现场操作配合使用。 三、程序设计 1、程序流程图

单片机实验程序(全)

2基本输入输出实验(蜂鸣器控制程序) /******************************************************* 名称:基本输入输出(I/O)程序 说明: ********************************************************/ #include //包含头文件 #define uint unsigned int //宏定义 #define uchar unsigned char sbit buzzer=P3^5; sbit Keyadd=P2^0; sbit Keydec=P2^1; sbit Keycom=P2^2; void Delay(uint z) { uint x; uchar y; for(x=z;x>0;x--) //延时 { for(y=250;y>0;y--); } } void main(void) { uchar voice; voice=3; while(1) { if(Keyadd==0) //按键被按下时为0 voice=1; if(Keydec==0) voice=2; if(Keycom==0) voice=3; if(voice==1) {buzzer=~buzzer; Delay(1); } else if(voice==2) {buzzer=~buzzer; Delay(20); } else buzzer=1; } }

3定时器中断实验 /******************************************************* 名称:实验三作业 说明: ********************************************************/ #include //包含头文件 #define uint unsigned int //宏定义 #define uchar unsigned char uchar counter; uchar voice; sbit buzzer=P3^5; sbit Keyadd=P2^0; sbit Keydec=P2^1; sbit Keycom=P2^2; sbit Keycan=P2^3; //----------------计算计数器初值-----------------// #define T0_TIME1 254 //定时时间us为单位 #define T0ReLoadL1 ((65536-(uint)(T0_TIME1*11.0592/12)) % 256) #define T0ReLoadH1 ((65536-(uint)(T0_TIME1*11.0592/12)) / 256) //----------------计算计数器初值-----------------// #define T0_TIME2 1400 //定时时间us为单位 #define T0ReLoadL2 ((65536-(uint)(T0_TIME2*11.0592/12)) % 256) #define T0ReLoadH2 ((65536-(uint)(T0_TIME2 *11.0592/12)) / 256) /********************************************************* 名称:主程序 说明: **********************************************************/ void main(void) { //-----------------------------初始化TIMER0 TMOD|=0x01; //定时器T0方式1 TH0 =T0ReLoadH1; //装载计数器初值 TL0 =T0ReLoadL1; TR0 =1; //启动Timer0 ET0 =1; //Timer0中断使能 EA =1; //总开关使能 //-----------------------------大循环 counter=0;

单片机实验程序

一 #include #include #define uchar unsigned char sbit H1=P3^6; sbit H2=P3^7; sbit L1=P0^5; sbit L2=P0^6; sbit L3=P0^7; tab1[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff,0xff,0xff,0xff}; tab2[]={0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3b,0x37,0x2f,0x1f}; tab3[]={0xff,0xff,0xff,0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; tab4[]={0x1f,0x2f,0x37,0x3b,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f}; void Delay1s() //@11.0592MHz { unsigned char i,j,k; for(i=10;i>0;i--) for(j=200;j>0;j--) for(k=250;k>0;k--) } void delay20ms() { unsigned char i,j; for(i=100;i>0;i--) for(j=60;j>0;j--); } void flick() { uchar d; while(d<=2) { P2=0x00; P3=0xc3; Delay1s(); P2=0xff; P3=0xff; Delay1s(); d++; } } void main() { uchar b,y,n; flick();

单片机试验源程序文件

单片机实验指导书(实验源程序)

实验二、三I/O接口实验 1、输出实验 例1: ORG 0000H AJMP START ;跳转到初始化程序 ORG 0033H ;----- 主程序开始----- START: MOV P1,#0FFH ;是所有LED熄灭 ACALL DELAY ;调用延时子程序 CLR P1.0 ;P1.0输出低电平,使LED3点亮 ACALL DELAY ;调用延时子程序 SETB P1.0 ;P1.0输出高电平,使LED3熄灭 CLR P1.1 ;P1.1输出低电平,使LED4点亮 ACALL DELAY ;调用延时子程序 SETB P1.1 ;P1.1输出高电平,使LED4熄灭 CLR P1.2 ;P1.2输出低电平,使LED5点亮 ACALL DELAY ;调用延时子程序 SETB P1.2 ;P1.2输出高电平,使LED5熄灭 CLR P1.3 ;P1.3输出低电平,使LED6点亮 ACALL DELAY ;调用延时子程序 MOV P1, #0F0H ;LED3~LED6全部发光 ACALL DELAY ;调用延时子程序 AJMP START ;返回到标号START处再循环 ;----- 延时子程序----- DELAY: MOV R5,#10 LOOP: MOV R6,#200 LOOP1: MOV R7,#250 LOOP2: DJNZ R7,LOOP2 DJNZ R6,LOOP1 DJNZ R5,LOOP RET 例2: ORG 0000H AJMP START ;跳转到初始化程序 ORG 0033H ;----- 主程序开始----- START: MOV P1,#0FFH ;是所有LED熄灭 ACALL DELAY ;调用延时子程序 MOV ACC,#0FEH ;ACC中先装入LED3亮的数据(二进制的11111110) MOV P1,ACC ;将ACC的数据送P1口 ACALL DELAY ;调用延时子程序 MOV R0,#03H ;上句送到P1口的数据就点亮了LED1,所以将数据再移

单片机实验二

单片机实验报告二 姓名 学号 时间 地点 实验题目 I/O 口输入、输出实验 一、实验目的 1. 学习I/O 口的使用方法。 2. 学习延时子程序、查表程序的编写和使用。 二、实验主要仪器和环境 PC 机、W A VE 软件、仿真器+仿真头、实验板、电源等。 三、实验说明 本实验第一部分通过单片机的I/O 口控制LED 的亮灭,从而观察I/O 口的输出。实验第二部分通过单片机的I/O 口接受按键动作信息,然后通过LED 和数码管指示。通过本实验学生可以掌握单片机I/O 口输入输出的控制方法,同时也可以掌握单片机延时子程序、查表程序的编写和调试方法。要求预先编写好程序并通过伟福仿真软件调试。 四、实验内容 1、P0口做输出口,接八只LED ,编写程序,使LED 循环点亮,间隔0.5秒。 2、 P1.0--P1.7作输入口接拨动开关S0--S7;P0.0--P0.7作输出口,接发光二极管L1—L8,编写程序读取开关状态,将此状态在对应的发光二极管上显示出来,同时将开关号(0—7)显示在LED 数码管上。编程时应注意P1作为输入口时应先置1,才能正确读入值。 五、实验电路连线 P0.0 ---- LED0 P1.0 ----- S1 P0.1 ---- LED1 P1.1 ----- S2 P0.2 ---- LED2 P1.2 ----- S3 P0.3 ---- LED3 P1.3 ------ S4 P0.4 ---- LED4 P1.0 ------ S5 P0.5 ---- LED5 P1.0 ------ S6 P0.6 ---- LED6 P1.0 ------ S7 P0.7 ---- LED7 P1.0 ------ S8 实验1:P0口循环点灯 实验2:P1、P0口输入输出 评 阅

单片机实验程序

工业顺序控制(INT0.INT1综合实验) ;掌握工业顺序控制的简单编程,中断的使用ORG 0000H SJMP MAIN ORG 0013H LJMP INTO MAIN: MOV P1,#00H ORL P3,#00H PO11: JNB P3.4,PO11 ;开工吗? ORL IE,#84H ORL IP,#04H MOV PSW,#00H ;初始化 MOV SP,#53H PO12: MOV P1,#01H ;第一道工序ACALL PO1BH MOV P1,#02H ;第二道工序 ACALL PO1BH MOV P1,#04H ;第三道工序 ACALL PO1BH MOV P1,#08H ;第四道工序 ACALL PO1BH MOV P1,#10H ;第五道工序 ACALL PO1BH MOV P1,#20H ;第六道工序 ACALL PO1BH MOV P1,#40H ;第七道工序 ACALL PO1BH SJMP PO12 INTO: MOV B,R2 ;保护现场 PO17: MOV P1,#00H ;关输出 MOV 20H,#0A0H ;振荡次数 PO18: SETB P1.7 ;振荡 ACALL PO1A ;延时 CLR P1.7 ;停止 ACALL PO1A ;延时 DJNZ 20H,PO18 ;不为零转 CLR P1.7 ACALL PO1A JNB P3.3,PO17 ;故障消除吗? MOV R2,B ;恢复现场 RETI PO19: MOV R2,#10H ;延时1

RET PO1A: MOV R2,#06H ;延时2 ACALL DELY RET PO1BH: MOV R2,#30H ;延时3 ACALL DELY RET DELY: PUSH 02H ;延时子程序DEL2: PUSH 02H DEL3: PUSH 02H DEL4: DJNZ R2,DEL4 POP 02H DJNZ R2,DEL3 POP 02H DJNZ R2,DEL2 POP 02H DJNZ R2,DELY RET END

单片机实验报告

目录 一、实验一 (1) 二、实验二 (7) 三、实验三 (11) 四、实验四 (15)

实验一定时/计数器验证实验 一、实验目的 熟悉定时/计数器T0的特点,学会合理选择定时方式并能根据具体情况结合软件的方式定时。 二、实验设备及器件 IBM PC机一台 PROTEUS 硬件仿真软件 Keil C51。 三、实验内容 用AT89C51单片机的定时/计数器T0产生1s的定时时间,作为秒计数时间,当1s产生时秒计数加1;秒计数到60时,自动从0开始。 四、实验要求 要求采用Proteus软件实现上述实验。 五、实验步骤 1.打开Proteus ISIS编辑环境,按照表1-1所列的元件清单添加元件。 表1-1 元件清单 元件全部添加后,在Proteus ISIS的编辑区域中按图1-1所示的原理图连接硬件电路。

图1-1 电路原理图 2.根据参考程序绘出流程图,并辅以适当的说明。 流程图如图1-2所示:

图1-2 程序流程图 3.打开KeilμVision4,新建Keil项目,选择AT89C51单片机作为CPU,将参考 程序导入到“Source Group 1”中。在“Options for Target”对话窗口中,选中“Output”选项卡中的“Create HEX File”选项和“Debug”选项卡中的“Use:Proteus VSM Simulator”选项。编译汇编源程序,改正程序中的错误。 4.在Proteus ISIS中,选中AT89C51并单击鼠标左键,打开“Edit Component” 对话窗口,设置单片机晶振频率为12MHz,在此窗口中的“Program File” 栏中,选择先前用Keil生成的.HEX文件。在Proteus ISIS的菜单栏中选择“File”→“Save Design”选项,保存设计,在Proteus ISIS的菜单栏中,打开“Debug”下拉菜单,在菜单中选中“Use Remote Debug Monitor”选项,以支持与Keil的联合调试。 5.在Keil的菜单栏中选择“Debug”→“Start/Stop Debug Session“选项,

单片机实验程序及流程图

《单片机技术》实验多媒体讲义《单片机技术》实验多媒体讲义《单片机技术》实验多媒体讲义

三.程序清单及程序流程框图 ORG 0000H Array LJMP MAIN MAIN: MOV R0,#30H MOV R2,#10H CLR A A1: MOV @R0,A INC R0 INC A DJNZ R2,A1 MOV R0,#30H MOV R1,#40H MOV R2,#10H A2: MOV A, @R0 MOV @R1,A INC R0 INC R1 DJNZ R2, A2 MOV R1,#40H MOV DPTR ,#4800H MOV R2, #10H A3: MOV A,@R1 MOVX @DPTR ,A INC R1 INC DPTR DJNZ R2,A3 MOV SP,#60H MOV R2,#10H MOV DPTR ,#4800H PUSH DPL PUSH DPH MOV DPTR,#5800H MOV R3,DPL MOV R4,DPH A4: POP DPH POP DPL MOVX A,@DPTR INC DPTR PUSH DPL PUSH DPH MOV DPL,R3

MOV DPH,R4 MOVX @DPTR,A INC DPTR MOV R3,DPL MOV R4,DPH DJNZ R2,A4 MOV R0,#50H MOV DPTR,#5800H MOV R2,#10H A5: MOVX A,@DPTR MOV @R0,A INC R0 INC DPTR DJNZ R2,A5 POP DPH POP DPL HERE: LJMP HERE END

单片机实验程序

一 1.修改例程一的源程序 (1)将A寄存器的初值改为80H(正逻辑,数据位为1 表示发光 二极管点亮),再对源程序进行简单修改,使程序运行后发光二极管情况与修改前相同。 (2)将LED向左循环移位点亮改为向右循环移位点亮 (3)加快LED循环移位点亮的速度 $include(C8051F020.inc) ;C8051F02x 系列单片机信息头文件包含伪指令 INIT: LCALL Init_Device 调用初始设置子程序 (1)MOV A,#080H ;赋初始值并在发光二极管上显示该数值 CPL A MOV P3,A LOOP: CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY (2)RL A ;A 寄存器内容右移1 位并送1 发光二极管显示MOV P3,A AJMP LOOP ;无限循环 DELAY: MOV R5,#0H ;延时子程序 D1: MOV R6,#00H DJNZ R6,$ DJNZ R5,D1 RET $include(Init_Device.inc);初始设置子程序文件包含伪指令 END (3)可删除几个CALL DELAY 语句即可加快循环速度

2.将例程二0——F 的循环显示改为0——9的循环显示 $include(C8051F020.inc) ;C8051F02x 系列单片机信息头文件包含伪指令 ORG 0000H LJMP INIT TAB:DB 0C0H,0F9H,0A4H,0B0H,099H,092H,082H,0F8H;字符段码表0-7 DB 080H,090H ;字符段码表8-F INIT: lcall Init_Device ;调用初始设置子程序 INIT1: MOV R1,#00H ;操作数据初始值 MOV A,R1 MAIN: MOV DPTR,#TAB;读取与A 中数值对应的显示段码 MOVC A,@A+DPTR MOV P5,A ;段码送并行口1显示 CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY CALL DELAY INC R1 ;操作数据(R1)增1 MOV A,R1 C C C C C,#0AH,MAIN;检查操作数据是否大于显示范围(F) SJMP INIT1 ;无限循环 D D D D D: MOV R5,#0H ;延时子程序 D1: MOV R6,#0H DJNZ R6,$ DJNZ R5,D1 RET $include(Init_Device.inc);初始设置子程序文件包含伪指令 END

51单片机实验程序

用查表方式编写y=x13+x23+x33。(x为0~9的整数) #include void main() { int code a[10]={0,1,8,27,64,125,216,343,512,729};//将0~9对应的每位数字的三次方的值存入code中,code为程序存储器,当所存的值在0~255或-128~+127之间的话就用char,而现在的值明显超过这个范围,用int较合适。int的范围是0~65535或-32768~32767。 int y,x1,x2,x3;//此处定义根据习惯,也可写成char x1,x2,x3但是变量y一定要用int 来定义。 x1=2; x2=4; x3=9;//x1,x2,x3三个的值是自定的,只要是0~9当中的数值皆可,也可重复。 y=a[x1]+a[x2]+a[x3]; while(1);//单片机的程序不能停,这步就相当于无限循环的指令,循环的内容为空白。} //结果的查询在Keilvision软件内部,在仿真界面点击右下角(一般初始位置是右下角)的watch的框架内双击“double-click or F2 to add”文字输入y后按回车,右侧会显示其16进制数值如0x34,鼠标右键该十六进制,选择第一行的decimal,可查看对应的10进制数。 1、有10个8位二进制数据,要求对这些数据进行奇偶校验,凡是满足偶校验 的数据(1的个数为偶数)都要存到内RAM50H开始的数据区中。试编写有关程序。 #include void main() { int a[10]={0,1,5,20,24,54,64,88,101,105};//将所要处理的值存入RAM中,这些可以根据个人随意设定,但建议不要超过0~255的范围。 char i; //定义一个变量 char *q=0x50; //定义一个指针*q指向内部0x50这个地址。 for(i=9;i>=0;i--)//9~0循环,共十次,也可以用for(i=0;i<10;i++) { ACC=a[i];//将a[i]的值赋给累加器ACC if (P==0)//PSW0位上的奇偶校验位,如果累加器ACC内数值1的个数为偶数那么P为0,若为奇数,P为1。这里的P是大写的。 { *q=a[i]; q++;//每赋一个值,指针挪一个位置指向下一个。 } }

单片机实验二

实验二查表程序实验 一、实验目的 1. 熟悉51单片机指令系统。 2. 掌握查表程序的编制方法。 二、实验装置 PROTEUS教学实验系统。 三、实验内容 1. R2寄存器存有数0~9的BCD码,利用查表程序求其平方值,并存于R0所指的内部数据存储器中,先将0~9的平方值的BCD码存于程序存储器中,标号为TABLE。 源程序: ORG 0000H SJMP MAIN ORG 0040H MAIN: MOV R0, #30H MOV A, R2 ADD A, #03H MOVC A, @A+PC MOV @R0, A HE: SJMP HE TABLE: DB 00H, 01H, 04H, 09H, 16H DB 25H, 36H, 49H, 64H, 81H END 2. 上面的查平方值改为查0~9的立方值,此时,立方值的BCD码占了两个字节。请设计并调试该查表程序。 源程序: ORG 0000H SJMP MAIN ORG 0040H MAIN: MOV R0,#0030H MOV B,#02H MOV A,R2 MUL AB ADD A,#0EH MOVC A,@A+PC MOV @R0,A MOV R1,#31H MOV A,R2 MOV B,#02H MUL AB

ADD A,#04H MOVC A,@A+PC MOV @R1,A HE: SJMP HE TABLE: DB 00H,00H,00H,01H,00H,08H,00H,27H,00H,64H DB 01H,25H,02H,16H,03H,43H,05H,12H,07H,29H END 3. 表格长度加上偏移量大于256时,不能采用MOVC A,@A+PC指令,此时可用MOVCA,@A+DPTR指令。对于实验内容2采用MOVC A,@A+DPTR指令编写并调试一个查表程序。 源程序: ORG 0000H SJMP MAIN ORG 0040H MAIN:MOV R0,#30H MOV R1,#31H MOV A,R2 ADD A,R2 MOV DPTR,#TAB MOVC A,@A+DPTR MOV @R0,A MOV A,R2 ADD A,R2 INC DPTR MOVC A,@A+DPTR MOV @R1,A HE:SJMP HE TAB:DB 00H,00H,00H,01H,00H,08H,00H,27H,00H,64H,01H,25H,02H,16H,03H,43H,05H,12 H,07H,29H END 四、分析思考题 总结查表程序的设计方法。 查表程序有两种方法: 1:通过@A+PC方法,PC指的是这条指令的下条指令的地址,通过加该地址与表头地址的偏移量以及偏移量获得想要得到的数据(表中的值须和位置具有线性关系)。 2:通过@A+DPTR方法,DPTR指的是表首地址。比pc的方法简单,因为无需根据pc与表头之间的指令的大小计算偏移量。 实验二成绩:____________ 教师签名:_______________

单片机实验二程序

三.电路原理图 一、实验目的 1、熟悉Proteus软件和Keil软件的使用方法。 2、熟悉单片机应用电路的设计方法。 3、掌握单片机并行I/O口的直接应用方法。 4、掌握单片机应用程序的设计和调试方法。 二、设计要求 1、用Proteus软件画出电路原理图。要求在P1.0至P1.7口线上分别接LED0至LED7八个发光二极管,在P3.0口线上接一蜂鸣器。 2、编写程序:要求LED0至LED7以秒速率循环右移。 3、编写程序:要求LED0至LED7以秒速率循环左移。

4、编写程序:要求在灯移动的同时,蜂鸣器逐位报警。四.程序清单和流程图 程序清单: (一)右移 程序清单 ORG 0000H MOV A , #01111111B LOOP: MOV P1, A LCALL DELAY RR A LJMP LOOP DELAY: ;误差 0us MOV R7, #0A7H DL1: MOV R6, #0ABH DL0: MOV R5, #10H DJNZ R5, $ DJNZ R6, DL0 DJNZ RET END R7, DL1 NOP (二)左移 ORG 0000H MOV A , #11111110B LOOP: MOV P1, A LCALL DELAY RL A LJMP LOOP DELAY: ;误差 0us MOV R7, #0A7H DL1: MOV R6, #0ABH DL0: MOV R5, #10H DJNZ R5, $ DJNZ R6, DL0 DJNZ R7, DL1 NOP RET END (三)移位报警 ORG 0000H

MOV A, #01111111B LOOP: MOV P3, A SETB P1.0 LCALL DELAY CLR P1.0 LCALL DELAY RR A LJMP LOOP DELAY: ;误差 0us MOV R7,#17H DL1: MOV R6,#98H DL0: MOV R5,#46H DJNZ R5,$ DJNZ R6,DL0 DJNZ R7,DL1 RET END C语言: 左右移 #include #include #define uchar unsigned char #define uint unsigned int void delay(void) //误差 0us { uchar a,b,c; for(c=167;c>0;c--) for(b=171;b>0;b--) for(a=16;a>0;a--); _nop_(); //if Keil,require use intrins.h } void main(void) { uchar i,temp; while(1) { temp=0xfe; for(i=0;i<8;i++) { P3=temp; delay(); temp=_crol_(temp,1); } temp=0x7f; for(i=0;i<8;i++) { P3=temp;

相关主题
文本预览
相关文档 最新文档