中国石凳联盟 登录注册

【转贴】大家来玩MCU◎ ---(0010:MCU的结构)

rockage··2 回复·348 浏览

发表回复

http://erji.net/attachment/Mon_0710/6_37069_c83160f5ca36f2d.jpg





http://erji.net/attachment/Mon_0710/6_37069_b56113265b6a562.jpg





http://erji.net/attachment/Mon_0710/6_37069_6bd924617d77074.jpg






【关键词】:端口、程序及数据存储、程序活动
在上面一帖,我们运行了自己的小程序,看着这些指令做出的表现,可它们是如何在MCU的躯壳里活动的呢?
“不识庐山真面目 只缘身在此山中”---让我们把变焦镜头拉开,从整体上去看看MCU的框架结构吧!

一、MCU的I/O端口:
MCU 16F873A的输入输出端口参见图1,我用颜色来区分不同的组别,其中端口A本身就只有A0~A5共6条腿;端口B有两条已经被仿真器占用,只能用到B0~B5共6条腿;端口C端口最齐全,可以用全部的C0~C7全部8个端口。也就是说:对于16F873A这个MCU芯片,有20条I/O腿供我们自由支配使用。这些I/O腿还有很多复用的功能,大家可以从参考书了解,我们暂时只用到最基本的输入/输出功能。
如何分配MCU的I/O端口呢?这是一件很灵活的事情,如果用作单独的数字输入/输出,我们可以随便定义。但是有时考虑到成组数据的输出时(例如我们用来驱动8段的LED数码管),就要留出成组的I/O以便数据传送。
MCU的特殊功能腿,例如A/D转换、串口、SPI口等都是指定了某些腿的,要用到这些功能当然就不能随便更换了。有时候会遇到这样的尴尬:比如说:我们希望用成组的端口C0~C7来驱动LED数码管,同时又用到串口(C6和C7)跟外界通讯,这时就只好用另外的端口(如端口B)的其中两个口(如B0、B1)来代替C6、C7,当通过端口C给LED数码管送数据的时候,要单独测试数据中的第6、7位是高还是低,然后用位指令去置高/置低B0、B1。

二、程序存储器空间:
这是MCU内部用来存放我们编写的程序的FLASH存储空间,不同的芯片有不同的容量,我们用的16F873A的程序存储分配图参见图2,当芯片上电复位时,程序会自动从复位向量0X00开始,但是接下来的0X04又是中断向量的入口,所以我们必须在0X0000这个入口安排一条无条件跳转指令:GOTO XXXX,跳到XXXX这个地址,避免了跟中断向量打架。这个XXXX放到什么地方合适呢?通常,中断向量会占有好几个存储空间,我们要给它预留出来,在上一讲的例程里我们没有用到中断,所以是跳到了0X07这个地方:
;==================================================
ORG 0X00 ORG是一条伪指令,用来设定程序从程序存储器的0X00地址开始存储和执行
NOP NOP 是一条空操作指令,不做什么事情,磨蹭一下而已
GOTO INIT_START 跳转到初始化程序段执行,因为接下来的房间,是用来存放将来会用到的中断 入口的

ORG 0X07 又是一条伪指令,表示下面的程序从0X07开始
INIT_START
;==================================================
我们的程序就从0X07这个地方开始,循序地存放在后面的“FLASH房间”里面了。

三、数据存储器空间:
在单片机运行中,程序如同一个厨师,按照步骤做菜,数据就是任由厨师加工的荤素食材。16F873A内部用来存放数据的RAM单元的分布图见图3,其中绿色部分是我们可以存放数据的通用RAM空间,其他的是用来存放MCU的硬件资源例如I/O口、定时器、状态寄存器、累加器等部件所对应的特殊功能寄存器的空间。通用RAM空间还分布在4个不同的页面,由页面选择指令来识别。
【关于页面】:
由于指令寻找的地址空间的限制,MCU不能一下子直接给所有存放数据的“房间”编上不同的房号,在16F873A中,只能寻找到128个“房间”我们把它们分配在4个楼层(页面),寻找“房间”(寻址)的时候,我们分别用“一楼2号”,“二楼2号”来区分不同的“房间”。这就是页面设置的含义。

四、程序在MCU躯壳里的活动:
我们在上一讲的例程中可以看到:当我们定义了MCU的一些腿用来作为输入(感知按键的变化);一些腿作为输出(用来点亮LED)后,我们就可以把程序“放”在相应的程序存储区,然后就可以运行了。由于这个例程很简单,我们暂时还没有用到通用数据寄存器,但不能说我们的厨师没有“食材”,我们的数据变化是在端口A,和端口B的特殊功能寄存器里面的,我们感知的按键变化,被映射到端口A的“PORTA”寄存器;我们改变LDE发光的数据映射在“PORTB”寄存器里。

最后给出一个新的例程:
(文本文件可以在这里下载:id=2066star=1#2066" target=_blank

http://www.little-tube.com/bbs/dispbbs.asp?boardid=3id=2066star=1#2066

)

=================================================
TITLE DEMO_LED PROGRAM
(C) copyright by Little Dot CO,.LTD.
DESIGN DATE BEGIN: 2007/10/16
FINISH: 2007/10/16 (V1.0)
Programan: My
=================================================
本程序是一个演示MCU的I/O端口输入、输出的示范程序,
当四个开关K1~K4任意按下时,相应的LED5~LDE8就会分别
显示出:
1、2、3、4 四个字符

list p=16f873A

#include


***********************************************
* Variable definitions *
***********************************************
K1 EQU .2 PORTA
K2 EQU .3
K3 EQU .4
K4 EQU .5 以上定义了端口A的A2~A4作为按键输入端口
W1 EQU .0 PORTB
W2 EQU .1
W3 EQU .2
W4 EQU .3 以上定义了端口B的B0~B3作为点亮4个位LED的输出端口
================================================

ORG 0X00
NOP
GOTO INIT_START

ORG 0X07
INIT_START
CLRF PORTA
BSF STATUS,RP0
MOVLW B00111100 RA2-4 INPUT
MOVWF TRISA
MOVLW B10000110 Select all digital
MOVWF ADCON1
BCF STATUS,RP0
CLRF PORTB
BSF STATUS,RP0
MOVLW B11110000 RB0-3 OUTPUT
MOVWF TRISB
BCF STATUS,RP0
CLRF PORTC
BSF STATUS,RP0
MOVLW B00000000 RC ALL OUTPUT
MOVWF TRISC
BCF STATUS,RP0
MOVLW 0X3C
MOVWF PORTA 把A2~A4拉高
MOVLW 0X0F 把B0~B3拉高,相当于从正端先关闭4个数码管。
MOVWF PORTB
MOVLW 0XFF
MOVWF PORTC 拉高端口C,相当于从负端关闭4个数码管的7个笔画段。

========================================
Main_Loop:
NOP

TEST_K1:
BTFSC PORTA,K1 测试按键1是否按下?
GOTO TK_1
BCF PORTB,W1 如果按下,先打开第一位LED的上端。
MOVLW 0XF9 再把要显示的笔画段码送到端口C,点亮“1”
MOVWF PORTC 所需要的各段(这对应于LED数码管的下端)
GOTO TEST_K2
TK_1: BSF PORTB,W1 如果没按下,则关闭第一位LED的上端
TEST_K2:
BTFSC PORTA,K2 第二位:和第一位同样的处理
GOTO TK_2
BCF PORTB,W2
MOVLW 0XA4
MOVWF PORTC
GOTO TEST_K3
TK_2: BSF PORTB,W2
TEST_K3:
BTFSC PORTA,K3 第三位:和第一位同样的处理
GOTO TK_3
BCF PORTB,W3
MOVLW 0XB0
MOVWF PORTC
GOTO TEST_K4
TK_3: BSF PORTB,W3
TEST_K4:
BTFSC PORTA,K4 第四位:和第一位同样的处理
GOTO TK_4
BCF PORTB,W4
MOVLW 0X99
MOVWF PORTC
GOTO TEST_END
TK_4: BSF PORTB,W4

TEST_END: goto Main_Loop

================================================
END


大家请自行分析一下点亮4个LED的段码“0XF9”、“0XA4”、“0XB0”、“0X99”的含义,答对的奖励LCD液晶模块一个,呵呵。。。

【下讲提要】:汇编程序的结构、定时中断

点赞0 收藏
现用的lcd或led显示,一般分动态扫描驱动和静态驱动,动态的需要轮流扫描每一个显示点或者段,较为复杂些,以前做过些项目,后来用专用动态驱动的IC方便很多,只用向这个IC的特定位置写入要显示的内容,怎么轮扫就不管了。
静态驱动的,每个点或段,分别对应1个驱动端口,相对简单。
杨老师用的就是静态驱动。

七段数码管的字型代码表如下表(算小数点h就是8段):
a
-----
f b
----- g
e c
----- 。h
d


一般而言,这8段可以对应1个字节的8个位,二进制位按从低到高排列,也就是hgfedcba,代表1个字节的8位二进制11111111。

共阴接法显示字形:
g f e d c b a 段码
0 0 1 1 1 1 1 1 3fh
1 0 0 0 0 1 1 0 06h
2 1 0 1 1 0 1 1 5bh
3 1 0 0 1 1 1 1 4fh
4 1 1 0 0 1 1 0 66h
5 1 1 0 1 1 0 1 6dh
6 1 1 1 1 1 0 1 7dh
7 0 0 0 0 1 1 1 07h
8 1 1 1 1 1 1 1 7fh
9 1 1 0 1 1 1 1 6fh
A 1 1 1 0 1 1 1 77h
b 1 1 1 1 1 0 0 7ch
C 0 1 1 1 0 0 1 39h
d 1 0 1 1 1 1 0 5eh
E 1 1 1 1 0 0 1 79h
F 1 1 1 0 0 0 1 71h


共阴数码管高电平点亮,而共阳数码管是低电平点亮,因此编码就如下表:


7段数码译码表

http://erji.net/attachment/Mon_0711/6_50397_f96167e6cb1ede6.gif

为什么是“0XF9”、“0XA4”、“0XB0”、“0X99”,查表就可以看到了。
想显示什么,查表找到对应的编码替换即可。
自己也可显示 “U”,“ n”,“-”一类的,当然,W是显示不出来的
点赞0 收藏
发表回复
发表回复