单片机这个函数发生器 单片机的区别

  1、函数的声明    为了使C程序和汇编程序相互调用,要求汇编程序必须遵循C51中函数名的转换规则,否则将无法实现程序的相互调用。C51中函数名的转换规则如下表所示。
C51函数声明
转换函数名
void func (void)
无参数传递或参数不通过寄存器传递的函数,其函数名不作改变转入目标文件中
void func (char)
带有用寄存器传递参数的函数,在其名字前加上前缀&_&作为区别,表明函数包含寄存器内的参数传递
void func (void) reentrant
对于再入函数,在其名字前加上前缀&_?&作为区别,它包含堆栈内的参数传递
  2、段的命名规则    C51程序模块被编译后,其中的函数都以&?PR?函数名?模块名&为名的命名规则被分配到CODE段中;而函数中的DATA和BIT对象则以&?函数名?BYTE&和&?函数名?BIT&的命名规则建立DATA和BIT段。在C51程序和汇编程序相互调用时,汇编语言必须遵循C51中有关段名命名规则,其命名规则如下表所示。
?PR?函数名?模块名(所有模式)
?DT?函数名?模块名(SMALL模式)
?PD?函数名?模块名(COMT模式)
?XD?函数名?模块名(LARGE模式)
局部bit变量
?BI?函数名?模块名(所有存储器模式)
  以下给出一个示例:    ;**********汇编程序使用A51进行编译、    调试**********    NAMES;定义模块名    ?PR?SCAN_KEY?SCAN    定义程序代码段    PUBLSCAN_KEY;定义公共符号,函数名    RSEG?PR?SCAN_KEY?SCAN;程序代码段    SCAN_KEY:;起始地址&&END    /***********C程序使用C51进行编译、    调试************/    #include&reg51.h&    externvoidscan_key();/*对外部被调函数的声明    */voiin(void)    {&&scan_key();/*调用汇编函数*/&&    }
本网站试开通微、小企业商家广告业务;维修点推荐项目。收费实惠有效果!欢迎在QQ或邮箱联系!
试试再找找您想看的资料
资料搜索:
查看相关资料 & & &
copyright & &广电电器(中国梧州) -all right reserved& 若您有什么意见或建议请mail: & &
地址: 电话:(86)774-2826670&查看: 447|回复: 0
第1章 单片机高效入门
51单片机轻松入门—基于STC15W4K系列(C语言版)
李友全 编著:
第1章 单片机高效入门1 认识单片机2 制作一个最简单的单片机实验电路3 使用Keil软件编写最简单的程序(点亮一个发光二极管)4 计算机程序下载到单片机5 I/O口4种工作模式6 流水灯实例7 I/O口输入测试8 软件仿真9 硬件仿真10 延时软件使用方法11 main()、void main()和int main()的区别12 printf 格式化输出函数(单片机与计算机通信)13 学习用实验板介绍
1 认识单片机
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-18.jpg (22.26 KB, 下载次数: 12)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-1.jpg (42.47 KB, 下载次数: 10)
00:30 上传
单片机全称是单片微型计算机(与计算机原理相同),外 形与普通集成电路相同,但普通集成电路功能是固定死 的,使用者无法更改,单片机的功能是可以通过编写程序 进行更改的。 51单片机主要发展历程: AT89C51(已停产)——AS89S51(已淘汰)—— STC89C52(2004年,已落后)——STC12系列 (2007年)——STC15F系列(2011年)—— STC15W系列(2014年,最新运用主流)。 本书主讲单片机型号:STC15W系列中的典型型 号:IAP15W4K58S4 ,辅助性的介绍STC15F2K60S2与STC15W408S 编程语言与开发环境:当今最流行的具有跨平台 优势的C语言与keil编译软件
0.png (101 KB, 下载次数: 11)
00:15 上传
C语言跨平台优势
不同的CPU使用不同的汇编指令,不通用,但C语言有优越的跨平台能力2 制作一个最简单的单片机实验电路
1.png (143.17 KB, 下载次数: 9)
00:15 上传
2.png (110.43 KB, 下载次数: 13)
00:15 上传
3.png (51.87 KB, 下载次数: 12)
00:15 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-19.jpg (7.46 KB, 下载次数: 15)
00:30 上传
5V供电电路
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-20.jpg (15.19 KB, 下载次数: 11)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-21.jpg (7.59 KB, 下载次数: 10)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-22.jpg (9.5 KB, 下载次数: 9)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-23.jpg (16.66 KB, 下载次数: 11)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-2.jpg (18.24 KB, 下载次数: 14)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-3.jpg (23.21 KB, 下载次数: 8)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-24.jpg (11.66 KB, 下载次数: 12)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-25.jpg (15.82 KB, 下载次数: 10)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-4.jpg (29.02 KB, 下载次数: 11)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-5.jpg (35.42 KB, 下载次数: 13)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-26.jpg (19.39 KB, 下载次数: 12)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-27.jpg (12.82 KB, 下载次数: 14)
00:30 上传
计算机串口外形
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-6.jpg (51.47 KB, 下载次数: 9)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-28.jpg (34.09 KB, 下载次数: 14)
00:30 上传
连接到计算机串口
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-7.jpg (22.89 KB, 下载次数: 12)
00:30 上传
3 使用Keil软件编写最简单的程序(点亮一个发光二极管)
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-29.jpg (20.86 KB, 下载次数: 10)
00:30 上传
1、安装Keil软件
2、安装汉子补丁
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-8.jpg (44.09 KB, 下载次数: 11)
00:30 上传
3、 新建工程:工程名与C文件名可随便输入,但不能有汉字,更不能与C语言的关键字或函数名称相同,否则会发生冲突(编译出现很多错误或警告)
Keil中输入程序代码
#include &STC15W4K.H&sbit P0_0 = P0^0; // sbit是位定义 void main () { P0_0=0; // 点亮LEDwhile(1); // 让程序停在这里 }4 计算机程序下载到单片机
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-9.jpg (144.02 KB, 下载次数: 8)
00:30 上传
5 I/O口4种工作模式
0.png (35.37 KB, 下载次数: 11)
00:16 上传
例1.5 最精简的流水灯实例(A)
6 流水灯实例#include &STC15W4K.H& // 注意宏定义语句后面无分号void delay100ms(){unsigned char i,j,k; // i,j,k由由软件计算出并验证正确。for(i=157;i&0;i--) // 注意后面没分号for(j=9;j&0;j--) // 注意后面没分号for(k=194;k&0;k--); // 注意后面有分号}void port_mode() // 端口模式(准双向、弱上拉){P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00; P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;}void main(){port_mode(); // 将单片机所有端口配置为准双向弱上拉方式while(1){P0 =~(1&&a++); 第一次运行时=&& 0000=&& 0001&&=&& 0=&[=&& size][=&& font][=&& color][=&& align][p=&17,& null,=&& left]delay100ms();
[color=rgb(0,& (a=&=0x08)& 允许左移8次。[=&& align]P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00; P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;}void main(){port_mode(); // 将单片机所有端口配置为准双向弱上拉方式 P2 = 0xFF; // P2口置弱上拉高电平输出while(1){P0 = P2; // 循环检测P2口输入电平高低。}}8 软件仿真
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-10.jpg (70.72 KB, 下载次数: 14)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-11.jpg (29.45 KB, 下载次数: 12)
00:30 上传
9 硬件仿真 n 在STC程序下载软件中首先选择“Keil仿真设置”页面,点击“添加型号和头文件到Keil 中”,在出现的目录选择窗口中,定位到Keil的安装目录(比如“C:Keil818”),“确 定”后出现“STC MCU型号添加成功”的提示信息,点“确定”。
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-12.jpg (39.86 KB, 下载次数: 10)
00:30 上传
n 保持IAP15W4K58S4实验电路仍然与电脑串口相连,如上图所示,先选择仿真芯片运 行时的R/C时钟频率或使用外部晶振,然后点击“将IAP15W4K58S4设置为仿真芯片”按 钮,给电路板上电,此时就将会有程序向芯片中下载,下载完成后仿真器便制作完成 了,IAP15W4K58S4设置成仿真芯片后,要想再变成一般的单片机无需任何操作,直接 将它当作单片机下载程序使用就可以了。
n 在Keil中新建项目,出现下图 对话框,选择“STC MCU Database”项,然后从列表 中选择相应的MCU型号,在此选择“STC15W4K32S4”,点击“OK”完成选择。
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-13.jpg (21.77 KB, 下载次数: 10)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-30.jpg (76.2 KB, 下载次数: 13)
00:30 上传
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-31.jpg (1020 Bytes, 下载次数: 9)
00:30 上传
然后按下图设置硬件仿真
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-32.jpg (1020 Bytes, 下载次数: 9)
00:30 上传
确认前面我们所创建的项目编译没有错误后,按“Ctrl+F5”或工具栏图标 开始调 试,若硬件连接无误的话,将会进入到与软件仿真类似的调试界面,只是现在可以一步一步 执行程序并控制硬件动作了)。有时进入调试环境可能会失败,首先检查仿真串口号选择是否有误,另外可将单片机断电 后重新上电试试,若使用的USB转串口,可将USB头断开几秒再插上,如果仍然不行,请检查程序代码是否占用了仿真调试接口(P3.0与P3.1 )。
10 延时软件使用方法
长时间延时,函数固定格式:void delay500ms() // 大范围精确延时函数{unsigned char i,j,k; // i,j,k由软件计算出确定。for(i=41;i&0;i--) // 注意后面没分号for(j=133;j&0;j--) // 注意后面没分号for(k=252;k&0;k--); // 注意后面有分号}短暂延时,函数固定格式:void delay (unsigned char t) // 小范围精确延时函数{while(--t);}
根据不同的延时时间修改函数中的变量 i,j,k 与 t 即可, i,j,k 与 t 由笔者编写的 软件直接计算得出
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-14.jpg (91.24 KB, 下载次数: 16)
00:30 上传
11 main()、void main()和int main()的区别
在C语言中main()和void main()区别:一个有返回值(没声明类型的 默认是返回值int型),一个无返回值,特别在单片机运用中由于主函数 没有其它函数调用它,所以返回的值也就没什么用。所以一般都写的 void main(),这时程序中不需要return语句,如果main()函数前没有void(默认为int),或者写为int main()程序中就必须有return语句,比如: int main() { return 0; // 表示程序正常退出 } 在单片机程序中一般写作void min()最方便,但在其它一些C编译器中,写作void main()编译是不能通过的,需要写成int main(),int main()是C语言的标准格式。12 printf 格式化输出函数(单片机与计算机通信)例1.8 计算机串口助手显示单片机内部简单信息 #include &STC15W4K.H&#include&&// 为使用KEIL自带的库函数printf而加入void printstar(){printf(&********************************&);}void print_message(){printf(&hello world&); // 最简单输出 printf(&How do you do!&); // 输出换行符 printf(&欢迎学习STC51单片机&); // 中文输出}void UART_init(void){// 下面代码设置定时器1TMOD = 0x20; //
定时器1工作于方式2(8位自动重装方式) TH1 = 0xFD; // 波特率:2MHZTL1 = 0xFD; // 波特率:2MHZ TR1 = 1;// 下面代码设置定串口AUXR = 0x00; // 很关键,使用定时器1作为波特率发生器,S1ST2=0SCON = 0x50; //
SM0.SM1=01(最普遍的8位通信),REN=1(允许接受) TI=1; // 很关键,使用printf函数时必须有此命令}void main() {
UART_init(); // 初始化串口 printstar(); // 输出************** print_message(); // 输出说明文字 printstar(); // 输出************** while(1) ; // 停在这里我们把例1.8程序下载到单片机中,打开程序下载软件的串口助手,接收缓冲区选择文本模式,波特率9600,打开串口,给实验板断电后上电,可以看到单片机发给计算机的信息如图1-67所示,如果显示 的个别字符出现乱码或连续接收大量数据显示不正常,可换用其它串口助手软件,比如“丁丁串口调试 助手SSCOM 3.3”即可解决。实验结果如下:
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-15.jpg (67.48 KB, 下载次数: 13)
00:30 上传
实 验 主 板
13 学习用实验板介绍由于后续章节实验很多,制作实验电路比较耗费时间,可以购买实验板产品。
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-16.jpg (149.44 KB, 下载次数: 8)
00:30 上传
SD卡与MP3实验板
%E7%AC%AC1%E7%AB%A0-%E5%8D%95%E7%89%87%E6%9C%BA%E9%AB%98%E6%95%88%E5%85%A5%E9%97%A8-17.jpg (110.66 KB, 下载次数: 9)
00:30 上传
Powered by更多公众号:MindMotion-MMCU上海灵动微电子股份有限公司用于MCU宣传及技术交流。最新文章对这篇文章不满意?您可以继续搜索:百度:搜狗:感谢您阅读8位单片机 16位 32位区别,本文可能来自网络,如果侵犯了您的相关权益,请联系管理员。QQ:2727人阅读
单片机驱动程序(1)
最开始学习C语言时,使用printf和scanf进行格式化输入输出十分方便。
学习单片机有很长时间了,之前要再屏幕上显示一个变量或者通过串口传出一些变量值观测的话,需要进行一系列的取余取整运算,很是麻烦。
最近又研究了一下keil中针对printf和scanf的实现机理,做了一些改动,实现了标准格式化输入输出,共大家参考。
1.printf函数在格式化输出时,向下调用了char putchar(char c);这个函数,在“stdio.h”里可以发现有这个函数,所以我们需要自己构造一个这样的函数,即通过串口putchar(),代码如下:
char putchar(char c)
hal_uart_putchar(c);
其中hal_uart_putchar(c);函数是我们比较熟悉的了,是51单片机通过串口发送一个字节的函数,具体代码如下:
void hal_uart_putchar(char i)
TI = 0; //清空发送完中断请求标志位
//将数据放入寄存器发送
while(TI == 0);//等待发送完毕,发送完毕 TI == 1
TI = 0; //清空发送完中断请求标志位
有了这两个函数,在单片机启动后,首先进行串口初始化,接着就可以使用printf了……是不是很简单……
-------------------------------------------------------------------------------------------------------------------------------------
2.下面再看scanf的具体实现方法:
scanf函数在格式化输入时,向下掉用了char getkey(void);这个函数,在“stdio.h”里可以发现有这个函数,所以我们需要自己构造一个这样的函数,即通过串口getkey(),代码如下:
char _getkey (void)
return hal_uart_getchar();
其中hal_uart_getchar();&稍稍复杂,但也很好理解,代码如下:
char hal_uart_getchar(void)
//Wait until a character is available:
while(uart_rx_cnt == 0);
ch = uart_rx[uart_rx_rp];
uart_rx_rp = (uart_rx_rp + 1) % UART_BUF_SIZE;
uart_rx_cnt--;
这个函数是从串口接收队列中取出队尾的一个字节。uart_rx_cnt&表示现在串口队列中的已有字节数,uart_rx_rp&指向队尾。
最后要介绍的一个函数是串口接收中断函数,代码如下:
void UART1InterruptReceive(void) interrupt 4
ES=0;//关串行口中断
RI=0;//接收中断信号清零,表示将继续接收
if(uart_rx_cnt & UART_BUF_SIZE)
uart_rx[uart_rx_wp] = SBUF;
uart_rx_wp = (uart_rx_wp + 1) % UART_BUF_SIZE;
uart_rx_cnt++;
ES=1;//开串行口中断
该函数实现了串口的中断接收,收到的新的字节存放在队首,即uart_rx_wp指向队列的首地址,每次收到一个新的字节,uart_rx_cnt增1。
至此,scanf函数也可以实现了。
测试截图:
注:串口接收的队列没有溢出检测……
这篇文章里实现的是对于串口的格式化输入输出,实际上,我们同样可以对hal_uart_getchar();和hal_uart_putchar(c);函数进行更改,实现在屏幕上的格式化输出等,思路都是一样的……
有不合理的地方,请大家批评指正。
源代码下载地址:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:23610次
排名:千里之外
原创:17篇
转载:17篇
(1)(1)(6)(6)(10)(8)(1)(1)单片机ram和rom的区别
查看: 1365|
摘要: 单片机运行时需要调用某个程序/函数/固定数据时就需要读取ROM,然后在RAM中执行这些程序/函数的功能,所产生的临时数据也都存在RAM内,断电后这些临时数据就丢失了。ROM:(Read Only Memory) 程序存储器在单片机中用来存储程序数据及 ...
运行时需要调用某个程序/函数/固定数据时就需要读取ROM,然后在RAM中执行这些程序/函数的功能,所产生的临时数据也都存在RAM内,断电后这些临时数据就丢失了。ROM:(Read Only Memory)
程序存储器在单片机中用来存储程序数据及常量数据或变量数据,凡是c文件及h文件中所有代码、全局变量、局部变量、const’限定符定义的常量数据、startup.asm文件中的代码(类似ARM中的bootloader或者X86中的BIOS,一些低端的单片机是没有这个的)通通都存储在ROM中。
RAM:(Random Access Memory)
随机访问存储器用来存储程序中用到的变量。凡是整个程序中,所用到的需要被改写的量,都存储在RAM中,“被改变的量”包括全局变量、局部变量、堆栈段。程序经过编译、汇编、链接后,生成hex文件。用专用的烧录软件,通过烧录器将hex文件烧录到ROM中(究竟是怎样将hex文件传输到MCU内部的ROM中的呢?),因此,这个时候的ROM中,包含所有的程序内容:无论是一行一行的程序代码,函数中用到的局部变量,头文件中所声明的全局变量,const声明的只读常量,都被生成了二进制数据,包含在hex文件中,全部烧录到了ROM里面,此时的ROM,包含了程序的所有信息,正是由于这些信息,“指导”了CPU的所有动作。可能有人会有疑问,既然所有的数据在ROM中,那RAM中的数据从哪里来?什么时候CPU将数据加载到RAM中?会不会是在烧录的时候,已经将需要放在RAM中数据烧录到了RAM中?要回答这个问题,首先必须明确一条:ROM是只读存储器,CPU只能从里面读数据,而不能往里面写数据,掉电后数据依然保存在存储器中;RAM是随机存储器,CPU既可以从里面读出数据,又可以往里面写入数据,掉电后数据不保存,这是条永恒的真理,始终记挂在心。清楚了上面的问题,那么就很容易想到,RAM中的数据不是在烧录的时候写入的,因为烧录完毕后,拔掉,当再给MCU上电后,CPU能正常执行动作,RAM中照样有数据,这就说明:RAM中的数据不是在烧录的时候写入的,同时也说明,在CPU运行时,RAM中已经写入了数据。关键就在这里:这个数据不是人为写入的,CPU写入的,那CPU又是什么时候写入的呢?听我娓娓道来。上回说到,ROM中包含所有的程序内容,在MCU上电时,CPU开始从第1行代码处执行指令。这里所做的工作是为整个程序的顺利运行做好准备,或者说是对RAM的初始化(注:ROM是只读不写的),工作任务有几项:
1、 为全局变量分配地址空间---à如果全局变量已赋初值,则将初始值从ROM中拷贝到RAM中,如果没有赋初值,则这个全局变量所对应的地址下的初值为0或者是不确定的。当然,如果已经指定了变量的地址空间,则直接定位到对应的地址就行,那么这里分配地址及定位地址的任务由“连接器”完成。
2、 设置堆栈段的长度及地址---à用C语言开发的单片机程序里面,普遍都没有涉及到堆栈段长度的设置,但这不意味着不用设置。堆栈段主要是用来在中断处理时起“保存现场”及“现场还原”的作用,其重要性不言而喻。而这么重要的内容,也包含在了编译器预设的内容里面,确实省事,可并不一定省心。平时怎么就没发现呢?奇怪。
3、 分配数据段data,常量段const,代码段code的起始地址。代码段与常量段的地址可以不管,它们都是固定在ROM里面的,无论它们怎么排列,都不会对程序产生影响。但是数据段的地址就必须得关心。数据段的数据时要从ROM拷贝到RAM中去的,而在RAM中,既有数据段data,也有堆栈段stack,还有通用的工作寄存器组。通常,工作寄存器组的地址是固定的,这就要求在绝对定址数据段时,不能使数据段覆盖所有的工作寄存器组的地址。必须引起严重关注。这里所说的“第一行代码处”,并不一定是你自己写的程序代码,绝大部分都是编译器代劳的,或者是编译器自带的demo程序文件。因为,你自己写的程序(C语言程序)里面,并不包含这些内容。高级一点的单片机,这些内容,都是在startup的文件里面。仔细阅读,有好处的。通常的做法是:普通的flashMCU是在上电时或复位时,PC指针里面的存放的是“0000”,表示CPU从ROM的0000地址开始执行指令,在该地址处放一条跳转指令,使程序跳转到_main函数中,然后根据不同的指令,一条一条的执行,当中断发生时(中断数量也很有限,2~5个中断),按照系统分配的中断向量表地址,在中断向量里面,放置一条跳转到中断服务程序的指令,如此如此,整个程序就跑起来了。决定CPU这样做,是这种ROM结构所造成的。其实,这里面,C语言编译器作了很多的工作,只是,你不知道而已。如果你仔细阅读编译器自带的help文件就会知道很多的事情,这是对编译器了解最好的途径。I/O口寄存器:也是可以被改变的量,它被安排在一个特别的RAM地址,为系统所访问,而不能将其他变量定义在这些位置。中断向量表:中断向量表是被固定在MCU内部的ROM地址中,不同的地址对应不同的中断。每次中断产生时,直接调用对应的中断服务子程序,将程序的入口地址放在中断向量表中。ROM的大小问题:对于flash类型的MCU,ROM空间的大小通常都是整字节的,即为ak*8bits。这很好理解,一眼就知道,ROM的空间为aK。但是,对于某些OTP类型的单片机,比如holtek或者sonix公司的单片机,经常看到数据手册上写的是“OTP progarming ROM 2k*15bit。。。。。”,可能会产生疑惑,这个“15bit”认为是1个字节有余,2个字节又不足,那这个ROM空间究竟是2k,多于2k,还是4k但是少了一点点呢?这里要明确两个概念:一个是指令的位宽,另一个是指令的长度。指令的位宽是指一条指令所占的数据位的宽度;有些是8位位宽,有些是15位位宽。指令长度是指每条指令所占的存储空间,有1个字节,有2个字节的,也有3个字节甚至4个字节的指令。这个可以打个形象的比方:我们做广播体操时,有很多动作要做,但是每个复杂的动作都可以分解为几个简单的动作。例如,当做伸展运动时,我们只听到广播里面喊“2、2、3、4、5、6、7、8”,而这里每一个数字都代表一个指令,听到“3”这个指令后,我们的头、手、腰、腿、脚分别作出不同的动作:两眼目视前方,左手叉腰,右手往上抬起,五指伸直自然并拢打开,右腿伸直,左腿成弓步······等等一系列的分解动作,而要做完这些动作的指令只有一个“3”,要执行的动作却又很多,于是将多个分解动作合并成一个指令,而每个分解动作的“位宽”为15bits。实事上也确实如此,当在反汇编或者汇编时,可以看到,复合指令的确是有简单的指令组合起来的。到此,回答前面那个问题,这个OTP的ROM空间应该是2K,指令位宽为15位。一般的,当指令位宽不是8的倍数时,则说明该MCU的大部分指令长度是一个字节(注:该字节宽度为15位,不是8位),极少数为2个或多个字节,虽然其总的空间少,但是其能容下的空间数据并不少。
上一篇:下一篇:
Powered by &
这里是—这里可以学习 —这里是。
栏目导航:

我要回帖

更多关于 函数发生器 单片机 的文章

 

随机推荐