完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
`````` 本帖最后由 friend0720 于 2016-9-23 10:18 编辑 前言 单片机是一门综合技术,它要求学习者具有一定的电子电路基础,和一定的 C 语言或汇编语言基础。当然如果你学习过《微机原理》那就更好了。C 语言是目前单片机开发最常用到的开发语言,因此请务必学好 C 语言。 同时单片机又是一门实践性很强的技术,如果不亲自动手搭建电路编写程序,是很难真正学会单片机的。下面说说单片机学习的主要过程: 1. 确定一款单片机作为自己的学习目标。目前主流8位单片机有stm8、AVR、PIC等。 2. 搜集该型单片机的各种学习资料。比如书籍、论坛帖子、视频教程等。 3. 下载并搭建软件开发环境 4. 购买硬件开发工具、烧录器、调试器、各种元器件。搭建单片机最小系统,编写程序驱动各种片内资源。 5. 扩展外围电路,并为之编写驱动程序。 后续本人将以ATmega16单片机为例,介绍具体的学习过程。下面是未来我们开发板的大致模样。
送给初学者的一句话:“勿在浮沙筑高台” 遥远的海 (待续) 附件加密!请勿下载! ``````
评分
|
||
相关推荐
715 个讨论
|
||
|
本帖最后由 friend0720 于 2016-3-4 23:32 编辑
新建一个STM32工程 使用D版J-Link仿真器的同学,请使用低版本MDK,否则可能造成仿真器失效。 1软件开发工具 本人比较偏好使用Keil进行STM32软件开发,虽然在STM32F407开发板上也使用过IAR开发环境,但本人还是更喜欢Keil。之前一直使用Keil uVision3.90版本,这次改用5.11版本。下载地址: http://www.cr173.com/soft/98310.html。 安装完MDK5后还需要到MDK官方网站下载并安装一个元件库,下载地址: http://www2.keil.com/mdk5/legacy/ 另外我们还需要到 ST 官网上下载一个 STM32F10X 的库函数开发包。下载地址: http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/LN1939/PF257890# 2新建一个工程 打开 MDK 选择菜单Project->New uVision Project ,新建一个工程。 弹出对话框中选择工程路径,输入工程名Test并保存。 弹出对话框中选择STMicroelectronics 下的 STM32F103C8,点击OK按钮。 选择 是。 拷贝STM32F10x固件库包下的文件夹 STM32F10x_StdPeriph_Driver到当前工程目录下,并在当前工程目录下建立StartUp和 USER 两个文件夹。 在STM32F10x固件库包中搜索并拷贝如上文件到StartUp 文件夹下。 在USER文件夹下建立以上两个空文件。 回到MDK中,删除掉工程默认建立的组。 新建三个组StartUp 、USER、FWLIB。 向工程中加入如上文件。 打开main.c文件输入如下内容并保存 #include "sys.h" int main(void) { while(1) { } } 打开 sys.h 文件输入如下内容并保存 #ifndef _SYS_H #define _SYS_H #include "stm32f10x.h" #include "stdio.h" #endif 点击工具栏中的魔术棒图标。 在弹出的对话框中选择C/C++标签,Define: 中输入如下内容:STM32F10X_MD,USE_STDPERIPH_DRIVER STM32F10X_MD 表示工程使用STM32中等容量产品 USE_STDPERIPH_DRIVER 表示工程使用STM32库函数 点击 IncludePaths 后面那个 … 按钮,弹出如下对话框: 向其中加入工程头文件包含路径。当前工程中有三个头文件路径需要包含,分别是StartUp、 USER,以及STM32F10x_StdPeriph_Driver文件夹下的inc目录。将来工程中出现新的头文件目录也需要在这里包含。 按F7键编译当前建立的工程。从Build Output窗口输出的信息可以看出,编译过程没有产生任何错误和警告,这说明我们的工程已经建立成功。 3仿真调试 点击工具栏中的魔术棒图标 弹出的对话框中选择Debug标签,左边那个Use Simulator 是纯软件仿真,我们选择右边那个 Use,下拉列表框中选择 J-LINK/J-TRACE Cortex(3.90版本中是Cortex-M3 J-LINK但本版本中没找到) 。点击Settings按钮。 弹出的窗口中选择 SW调试模式,时钟选择 5MHz(3.90版本中是10MHz),点击确定按钮。 点击工具栏中的 LOAD 按钮,编译好的代码就会被下载到芯片中。 点击工具栏上的 Debug按钮,我们就可以调试代码了。 遥远的海 (待续) |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-9-23 10:17 编辑
哈哈!不是大师,真的不是大师。在国内真正的大师不多。毕竟这些东西都是外国人发明的。 |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-3-11 12:08 编辑
STM32 原理篇目录 知其然还要知其所以然 程序是个啥玩意 STM32F1XX核心寄存器 STM32F1XX核心寄存器实验 系统启动模式 振荡器 STM32内核(Cortex-M3)的存储器映射 位带操作 STM32F10X中内置外设地址 内嵌 FLASH 存储器 内嵌 SRAM 存储器 电源系统管理 电压检测器 睡眠模式 停机模式 待机模式 实时时钟自动唤醒 AWU 方式 +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-3-4 23:35 编辑
程序是个啥玩意? 曾经在论坛里看到有人提问:“程序是如何让硬件工作的?”。当时我在想:“这人一定没学过数字电子”。想要说明这个问题,首先要知道程序是怎么来的。下面我用一些简单的例子说说程序到底是个啥玩意,它到底是如何产生和发展的。 1三极管的发明 1906年一个叫德福雷斯特的美国人,在弗莱明发明的二极管(电子管)基础上,发明了三极管,从此人类掌握了打开数字电子世界大门的钥匙。我们知道三极管除了能工作在放大状态,还能工作在导通和截至状态(即0和1的状态)。人们利用三极管这一特性,发明了各种时序电路和逻辑门电路。常见的逻辑门电路有与门、非门、或门、同或门、异或门、与非门等等。 常见逻辑门电路 聪明的灵长类动物将这些逻辑门电路组合起来,从而发明了更复杂的逻辑电路,38译码器就是其中的一种。灵长类动物发明的复杂逻辑电路千千万万,这里之所以只提及38译码器,是因为它逻辑简单,又比较常见,容易讲清楚。 38译码器 2 38译码器 学过数字电子的人都应该知道38译码器,简单讲就是3个脚输入,8个脚输出。 38译码器真值表 从38译码器真值表可以看出,当A[2,0]=000时Y[7,0]=11111110; 3 机器指令 下图是一个使用38译码器的简易电路图,我们暂时不考虑电路图的电器特性,只考虑其逻辑特性。那么我们如何令图中的发光二极管D0点亮呢?很简单,根据真值表,我们只要令A2=0、A1=0、A0=0即可。同理,如果我们令A[2,0]=111,那么发光二极管D7将被点亮。 很显然,想要点亮哪个LED,我们只要在真值表画红圈部分,找到对应的编码输入给A[2,0]即可。我们称真值表中画红圈这部分为38译码器的指令表,也就是说,它们就是38译码器这个逻辑器件的机器指令。 4第一个程序 到这里我们已经可以随心所欲的控制每个LED的亮灭了,那么我们如何让这些LED按照一定的顺序点亮呢?比如让LED从D0到D7依次点亮?我想你会说:“这太简单了”。是的,很简单。我们只要按照真值表中从上到下的顺序,把38译码器的机器指令依次赋值给A[2,0]即可: 000 ;D0亮 001 ;D1亮 010 ;D2亮 011 ;D3亮 100 ;D4亮 101 ;D5亮 110 ;D6亮 111 ;D7亮 恭喜你!世界上第一个程序诞生了,它很简单,很简陋,和你想想中的程序也许完全不是一回事,但它的的确确是一个程序。所谓“程序”,即事务执行的流程和顺序,在这里我们让LED按照我们想要的顺序点亮了,那么上面那些机器指令的组合就是一个不折不扣的程序。 到这里我们已经回答了开篇之初的那个问题。程序是一组有顺序(或有逻辑)的机器指令的组合,机器指令又是一组0和1的组合(即高低电平的组合),而0和1(高低电平)又控制着三极管的导通和关断,三极管是一个电子元件,它又可以控制其他的电子元件,就这么简单。那么接下来的问题是,程序是如何发展到今天这个样子的呢? 5 由二进制机器指令到汇编语言 1946年2月14日,世界上第一台电子计算ENIAC在美国宾夕法尼亚大学诞生。那时的程序员使用机器语言编写程序。38译码器的机器指令很简单,你可以很轻松的记住,但诸如101100000000000000000011 这样的机器指令恐怕就不那么好记忆了。我们可以想像,每天用机器指令写程序的人是多么的痛苦,多么的低效,多么的容易犯错误。于是聪明的灵长类动物想,可不可以使用一些简单的符号来代替那一长串的0、1组合呢。比如我们想让LED1点亮,我们就写 D1,想让LED6点亮就写D6。于是上面那个程序就变成了如下的形式: D0 ;D0亮 D1 ;D1亮 D2 ;D2亮 D3 ;D3亮 D4 ;D4亮 D5 ;D5亮 D6 ;D6亮 D7 ;D7亮 就这样,世界上第一个汇编语言程序诞生了。我们使用 D0-D7 代替了 000-111,这样写程序就方便很多了。等整个程序都写完了,我们只要到指令表中找到对应的机器指令翻译过来就好了,比如 D4出现的地方我们就把它翻译成机器指令 100。由此也可以看出,汇编指令和机器指令是一一对应的,它其实就是机器指令的一个方便记忆的符号,因此被称为“助记符”。 虽然,汇编语言使软件的编写方便了许多,但是人工将汇编代码翻译成机器指令这一过程非常费时费力,容易出错的。于是聪明的灵长类动物编写了一个程序,这个程序能够自动查找汇编指令对应的机器码,就这样世界上第一个汇编语言编译器诞生了。 6 高级语言的产生 汇编语言是软件发展史上的一大进步,但它也同样存在了许多的不完美。其中一项就是通用性比较差。比如我们家的38译码器汇编指令是 D0-D7,而你们家的可能就是 A0-A7,同是38译码器,我写的程序就是不能用到你们家的译码器上。又比如同样是计算1+1,我们家的汇编代码是 ADD 1,1 ; 而你们家的汇编代码却是 AAA 1,1 ; 为了解决这个问题,聪明的灵长类动物又发明了高级语言,其中最著名的莫过于C语言了。人们只要按照C语言的语法书写自己的代码,然后把写好的代码交给一个专门的程序,这个程序会自动的,把你的C代码翻译成目标机器的汇编代码。从此程序员要计算1+1这个难题,只要在C语言中写 “a=1+1;” 这个简单的语句就可以了,人们再也不必去关心这条语句被翻译成汇编语言是个什么样子,因为这一切都被编译器代劳了。但一些灵长类动物也为此付出了一定代价,它们永远也无法理解,在C语言加减乘除运算过程中出现的那个所谓的“神秘的中间变量”到底是什么。 我们可以认为汇编是对机器语言的一次封装, C 语言是对汇编语言的一次封装,随后出现的C++语言是对汇编语言的又一次升级式的封装。但事情到此并没有结束,如今更高级的封装形式“控件”已经非常流行了,而且在不久的将来,还会有新的,更高级的封装形式出现。 遥远的海
|
|
|
|
|
|
|
|
|
AVR难度和51一样吗?玩51 之后就学他吧。。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-3-4 23:36 编辑
STM32内核(Cortex-M3)的存储器映射 存储器映射是指把芯片中或芯片外的FLASH,RAM,外设,BOOTBLOCK等进行统一编址。即用地址来表示对象。这个地址绝大多数是由厂家规定好的,用户只能用而不能改。用户只能在挂外部RAM或FLASH的情况下可进行自定义。如图,是Cortex-M3存储器映射结构图。 Cortex-M3是32位的内核,因此其PC指针可以指向2^32=4G的地址空间,也就是0x0000_0000——0xFFFF_FFFF这一大块空间。 内部SRAM 区的大小是512MB,用于让芯片制造商连接片上的SRAM,这个区通过系统总线来访问。在这个区的下部,有一个1MB 的位带区,该位带区还有一个对应的32MB 的 “位带别名(alias)区”,容纳了8M个“位变量”(对比8051 的只有128 个位)。位带区对应的是最低的1MB 地址范围,而位带别名区里面的每个字对应位带区的一个比特。位带操作只适用于数据访问,不适用于取指。通过位带的功能,可以把多个布尔型数据打包在单一的字中,却依然可以从位带别名区中,像访问普通内存一样地使用它们。位带别名区中的访问操作是原子的,消灭了传统的“读-改-写”三步曲。 地址空间的另一个512MB 范围由片上外设(的寄存器)使用。这个区中也有一条32MB的位带别名,以便于快捷地访问外设寄存器。例如,可以方便地访问各种控制位和状态位。要注意的是,外设内不允许执行指令。 还有两个1GB 的范围,分别用于连接外部RAM 和外部设备,它们之中没有位带。两者的区别在于外部RAM 区允许执行指令,而外部设备区则不允许。 最后还剩下0.5GB 的隐秘地带,CM3 内核的闺房就在这里面,包括了系统级组件,内部私有外设总线,外部私有外设总线,以及由提供者定义的系统外设。 内嵌 Flash 存储器开始地址: 0x0800 0000 。 内嵌 SRAM 存储器开始地址: 0x2000 0000 。 外设管理寄存器开始地址: 0x4000 0000 。 |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-3-4 23:37 编辑
位带操作 支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM3中,有两个区中实现了位带。其中一个是SRAM 区的最低1MB 范围,第二个则是片内外设区的最低1MB 范围。这两个区中的地址除了可以像普通的RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。 下图从另一个侧面演示比特的膨胀对应关系 举例:欲设置地址0x2000_0000 中的比特2,则使用位带操作的设置过程如下图所示: 对应的汇编代码如图: 位带读操作相对简单些: bit_word_addr = bit_band_base + (byte_offset×32) + (bit_number×4) 其中: bit_word_addr是别名存储器区中字的地址,它映射到某个目标位。 bit_band_base是别名区的起始地址。 byte_offset是包含目标位的字节在位段里的序号 bit_number是目标位所在位置(0-31) |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-3-5 11:39 编辑
uCOS-II 移植1 基于 uC/OS-II v2.52 版本 要使 uCOS-II 正常运行,处理器必须满足以下要求: 处理器的C编译器能产生可重入代码; 处理器支持中断,并且能产生定时中断; 用C语言就可以开关中断; 处理器能支持一定数量的数据存储硬件堆栈; 处理器有将堆栈指针以及其他CPU寄存器的内容读出、并存储到堆栈或内存中去的指令。 uC/OS-II 硬件/软件体系结构 移植需要修改的部分 名称 类型 所在文件 语言类型 BOOLEAN 数据类型 OS_CPU.H C语言 INT8U 数据类型 OS_CPU.H C语言 INT8S 数据类型 OS_CPU.H C语言 INT16U 数据类型 OS_CPU.H C语言 INT16S 数据类型 OS_CPU.H C语言 INT32U 数据类型 OS_CPU.H C语言 INT32S 数据类型 OS_CPU.H C语言 FP32 数据类型 OS_CPU.H C语言 FP64 数据类型 OS_CPU.H C语言 OS_STK 数据类型 OS_CPU.H C语言 OS_CPU_SR 数据类型 OS_CPU.H C语言 OS_CRITICAL_METHOD 宏定义 OS_CPU.H C语言 OS_STK_GROWTH 宏定义 OS_CPU.H C语言 OS_ENTER_CRITICAL() 宏 OS_CPU.H C语言 OS_EXIT_CRITICAL() 宏 OS_CPU.H C语言 --------------------------------------------------------- OSStartHighRdy() 函数 OS_CPU_A.ASM 汇编 OSCtxSw() 函数 OS_CPU_A.ASM 汇编 OSIntCtxSw() 函数 OS_CPU_A.ASM 汇编 OSTickISR() 函数 OS_CPU_A.ASM 汇编 --------------------------------------------------------- OSTaskStkInit() 函数 OS_CPU.C C 语言 OSInitHookBegin() 函数 OS_CPU.C C 语言 OSInitHookEnd() 函数 OS_CPU.C C 语言 OSTaskCreateHook() 函数 OS_CPU.C C 语言 OSTaskDelHook() 函数 OS_CPU.C C 语言 OSTaskSwHook() 函数 OS_CPU.C C 语言 OSTaskStatHook() 函数 OS_CPU.C C 语言 OSTCBInitHook() 函数 OS_CPU.C C 语言 OSTimeTickHook() 函数 OS_CPU.C C 语言 OSTaskIdleHook() 函数 OS_CPU.C C 语言 附件加密!请勿下载!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-3-11 15:38 编辑
uCOS-II 移植2 INCLUDES.H INCLUDE.H 是一个主头文件,它出现在每个 .C 文件的第一行。这使得工程项目中的每个 .C 文件无需分别考虑它实际上需要哪些头文件。 可以通过重新编辑 INCLUDE.H ,增加自己的头文件,但是头文件必须添加在头文件列表的最后。虽然INCLUDE.H 文件与移植过程没有关系,但是因为每一个 uC/OS – II 的 C 文件都要使用它,所以在此说明一下。 #ifndef__INCLUDES_H__ #define__INCLUDES_H__ #include #include #include #include #include #include"ucos_ii.h" #include"os_cpu.h" #include"os_cfg.h" #endif |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-29 10:38 编辑
uCOS-II 移植3 OS_CPU.H OS_CPU.H 包括了用 #define 语句定义的、与处理器相关的常数、宏以及类型。 因为不同的微处理器有不同的字长,所以 uC/OS – II 的移植包括了一系列的数据类型定义,以确保其可移植性。uC/OS –II 代码从不使用 C 语言中的 short 、int 、long 等数据类型,因为它们是与编译器相关的,是不可移植的。 定义与编译器无关的数据类型 typedef unsigned char BOOLEAN; typedef unsigned char INT8U; typedef signed char INT8S; typedef unsigned short INT16U; typedef signed short INT16S; typedef unsigned int INT32U; typedef signed int INT32S; typedef float FP32; typedef double FP64; //处理器堆栈宽度(32 bit) typedef unsigned int OS_STK; //状态寄存器宽度(32 bit) typedef unsigned int OS_CPU_SR; 必须将任务堆栈的数据类型告诉 uC/OS-II 。这是通过为 OS_STK 声明恰当的 C 数据类型来实现的。如果处理器的堆栈是 32 位的,那么就应该将 OS_STK 声明为 : typedef INT32U OS_STK ; 如果移植过程中使用了处理器的状态寄存器,那么还必须声明 CPU 状态寄存器的数据类型。如果所用处理器的状态寄存器是 32 位宽度,那么只须做如下声明: typedef INT32U OS_CPU_SR; |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-29 11:37 编辑
uCOS-II 移植4 OS_CPU.H OS_STK_GROWTH 宏 绝大多数微处理器和微控制器的堆栈是从上往下递减的,但是也有某些处理器使用的是相反的方式。uC/OS-II 被设计成对2种情况都可以处理,只要使用OS_STK_GROWTH 宏指定堆栈的方向就可以了: #define OS_STK_GROWTH 0 表示堆栈由下往上递增; #define OS_STK_GROWTH 1 表示堆栈由上往下递增; OS_TASK_SW() 宏 OS_TASK_SW()是一个宏,uC/OS-II从低优先级任务切换到高优先级任务时必须用到。OS_TASK_SW() 总是在任务级代码中被调用。另一个函数 OSIntExit() 用在中断服务子程序 ISR 中。任务切换只是简单地将处理器的寄存器保存到将被挂起的任务的堆栈中,并且从堆栈中恢复运行的更高优先级的任务。OS_TASK_SW() 宏定义如下: #define OS_TASK_SW() OSCtxSw() 其中 OSCtxSw() 是一个使用汇编语言实现的函数,函数的具体实现将在后面分析。 临界区 实际上 OS_ENTER_CRITICAL() 和 OS_EXIT_CRITICAL() 两个宏总是成对使用的,并且分别加在临界代码的前面和后面。两个宏的实现方法如下: #define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();} #define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);} 其中 OS_CPU_SR_Save() 和 OS_CPU_SR_Restore(cpu_sr) 是使用汇编语言实现的两个函数,函数的具体实现将在后面分析,两个函数完成的功能如下: cpu_sr = OS_CPU_SR_Save(); //将PRIMASK寄存器内容保存到变量cpu_sr中,关中断 OS_CPU_SR_Restore(cpu_sr); //将变量 cpu_sr 中的内容恢复到PRIMASK寄存器中 cpu_sr 变量的声明如下: OS_CPU_SR cpu_sr=0; |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-29 11:37 编辑
uCOS-II 移植5 OS_CPU_C.C uC/OS-II 移植范例要求用户编写 10 个简单的C函数: OSTaskStkInit(); OSTaskCreateHook(); OSTaskDelHook(); OSTaskSwHook(); OSTaskIdleHook(); OSTaskStatHook(); OSTimeTickHook(); OSInitHookBegin(); OSInitHookEnd(); OSTCBInitHook()。 唯一必要的函数是OSTaskStkInit(),其它9个函数必须声明,但并不一定要包含任何代码。 OSTaskStkInit()函数被任务创建函数调用,在堆栈中做出该任务好像刚被中断一样的假象。 中断后STM32F3 寄存器 xPSR,PC,LR,R12,R3-R0 被自动保存到栈中,R11-R4如果需要保存,只能手工保存。因此 OSTaskStkInit() 的工作就是在任务自己的栈中保存cpu所有寄存器。这些值里 R1-R12 都没什么意义,这里用相应的数字代号主要是方便调试。 OS_STK * OSTaskStkInit(void (*task)(void *p_arg),void *p_arg,OS_STK *ptos,INT16U opt) { OS_STK *stk; void opt; stk=ptos; *(stk) = (INT32U)0x01000000L; /* xPSR 状态字寄存器 */ *(--stk) = (INT32U)task; /* Entry Point */ *(--stk) = (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/ *(--stk) = (INT32U)0x12121212L; /* R12 */ *(--stk) = (INT32U)0x03030303L; /* R3 */ *(--stk) = (INT32U)0x02020202L; /* R2 */ *(--stk) = (INT32U)0x01010101L; /* R1 */ *(--stk) = (INT32U)p_arg; /* R0 : argument */ /* Remaining registers saved on process stack */ *(--stk) = (INT32U)0x11111111L; /* R11 */ *(--stk) = (INT32U)0x10101010L; /* R10 */ *(--stk) = (INT32U)0x09090909L; /* R9 */ *(--stk) = (INT32U)0x08080808L; /* R8 */ *(--stk) = (INT32U)0x07070707L; /* R7 */ *(--stk) = (INT32U)0x06060606L; /* R6 */ *(--stk) = (INT32U)0x05050505L; /* R5 */ *(--stk) = (INT32U)0x04040404L; /* R4 */ return (stk); } xPSR = 0x01000000L,xPSR T 位(第24 位)置1,否则第一次执行任务时Fault, PC 指向任务入口, R14 = 0xFFFFFFFEL,最低4 位为E,是一个非法值,主要目的是不让使用R14,即任务是不能返回的。 R0 用于传递任务函数的参数,因此等于p_arg。 |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-29 11:38 编辑
uCOS-II 移植6 OS_CPU_A.ASM uC/OS-II 的移植实例要求用户编写4个简单的汇编语言函数: OSStartHighRdy(); OSCtxSw(); OSIntCtxSw(); OSTickISR(); 如果编译器支持插入行汇编代码,那么可以将所有与处理器相关的代码放到 OS_CPU_C.C 文件中,而不必再有单独的汇编语言文件。 OSStartHighRdy() 函数: OSStart() 函数调用 OSStartHighRdy() 来使就绪态任务中优先级最高的任务开始运行,这个函数的示意性代码如下: void OSStartHighRdy(void) { 调用用户定义的 OSTaskSwHook(); OSRunning = TRUE; 得到将要恢复运行任务的堆栈指针; Stack pointer = OSTCBHighRdy->OSTCBStkPtr; 从新任务堆栈中恢复处理器的所有寄存器; 执行中断返回指令; } OSCtxSw() 函数: 任务级的切换是通过执行软中断指令,或依据处理器的不同,执行 TRAP(陷阱)指令来实现的。这个函数的示意性代码如下: void OSCtxSw(void) { 保存处理器寄存器; 在当前任务的任务控制块中保存当前任务的堆栈指针; OSTCBCur->OSTCBStkPtr = Stack pointer; OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur= OSPrioHighRdy; 得到将要重新开始运行的任务的堆栈指针; Stack pointer = OSTCBHighRdy->OSTCBStkPtr; 从新任务的任务堆栈中恢复处理器所有寄存器的值; 执行中断返回指令; } OSIntCtxSw() 函数: OSIntExit() 函数通过调用 OSIntCtxSw() 函数,在 ISR 中执行任务切换功能。这个函数的示意性代码如下: void OSIntCtxSw(void) { 调用用户定义的 OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur= OSPrioHighRdy; 得到将要重新执行的任务的堆栈指针; Stack pointer = OSTCBHighRdy->OSTCBStkPtr; 从新任务堆栈中恢复所有处理器寄存器; 执行中断返回指令; } OSTickISR() 函数: uC/OS-II 要求用户提供一个周期性的时钟源,来实现时间的延迟和超时功能。是在节拍应该每秒发生 10~100次。必须在开始多任务后,即调用 OSStart() 后,启动时钟节拍中断;但由于 OSStart() 函数不会返回,用户无法实现这一操作。然而,可以在 OSStart() 运行后,uC/OS-II 启动运行的第一个任务中初始化节拍中断。这个任务是调用 OSStart() 之前建立的任务中优先级最高的任务。通常容易犯的错误是,在调用 OSInit() 和 OSStart() 之间打开了时钟节拍中断。OSTickISR() 示意代码如下: void OSTickISR(void) { 保存处理器寄存器; 调用 OSIntEnter() 或者直接给 OSIntNesting 加 1; if(OSIntNesting ==1 ) { OSTCBCur->OSTCBStkPtr = stack pointer; } 给产生中断的设备清中断; 重新允许中断(可选); OSTimeTick(); OSIntExit(); 恢复处理器寄存器; 执行中断返回指令; } |
|
|
|
|
|
|
|
|
本帖最后由 friend0720 于 2016-2-29 11:38 编辑
内嵌FLASH 存储器 内嵌 FLASH 存储器的地址是从 0x0800 0000 开始的,最多可达 1024KB .程序的写入可以通过 JTAG 接口使用仿真器实现,也可以通过称为 ISP 的方法下载。 FLASH 的擦写次数,典型值为 10K 次,最小值为 1K 次,因此写入次数过多有可能损坏芯片。在设计中一般不关心 FLASH 的读写,在程序中一般也不读写 FLASH 。 |
|
|
|
|
|
|
|
你正在撰写讨论
如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。
24 浏览 0 评论
567 浏览 0 评论
735 浏览 0 评论
901 浏览 0 评论
840 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
17069 浏览 31 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-15 13:42 , Processed in 1.143140 second(s), Total 74, Slave 67 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
13532