1

关于投票
关于μC/OS—II的串口通信模块设计(2)

3 串口通信模块的设计
每个串行端口有两个环状队列缓冲区,同时有两个信号量:一个用来指示接收字节,另一个用来指示发送字节。每个环状缓冲区有以下四个要素:
◇存储数据(INT8U数组);
◇包含环状缓冲区字节数的计数器;
◇环状缓冲区中指向将被放置的下一字节的指针;
◇环状缓冲区中指向被取出的下一字节的指针。
图3是接收数据软件模块的流程图。SerialGetehar()用来获取接收到的数据,假如缓冲区已空时将任务挂起,接收到字节时,任务将被唤醒,同时从串行口接收字节。SerialPutRxChar()用来将接收的字节放到缓冲区中,假如接收缓冲区已满,则该字节被丢弃。当字节插入到缓冲区中,SerialPutRxChar()通知数据接收信号量,使之将数据己到的消息传达给所有等待的任务。为防止挂起应用任务,可以通过调用SceiallsEmPty()去发现环状队列中是否有字节。 字串8

http://www.armforum.cn

图4是发送数据模块的流程图。当需要发送数据给串行端口时,SerialPurChar()等待信号量在初始化发送信号量时应该初始为缓冲区的大小。因此,当缓冲区中没有更多空间时,SerialPutChar()就挂起任务,只要UART再次发送字节,挂起任务就将恢复。SerialGctChar()被中断服务程序调用,假如发送缓冲区至少还有一个字节,Seri-a1GetChar()就返回一个从缓冲区发送的字节。假如缓冲区己空,则SerialGetChar()返回Null,这将使调用停止进一步的发送中断,一直到有数据发送为止。 字串5

字串8

4 异步串行通信的接口函数
应用任务可以通过如下的几个函数来控制和访问UART:SerialCfgPort()、SerialGetChar()、SerialInit()、SerialIsEmpty()、SerialIsFull()和SerialPutChar()。
SerialCfgPort()用于建立串行端口的特征,在为指定端口调用其他服务前,必须先调用该函数,包括确定波特率、比特数、奇偶校验和停止位等。
SerialGetChar()使应用程序从接收数据的环状缓冲区中取出数据。
SerialInit()用于初始化整个串口软件模块,且必须在该模块提供的其他任何服务前调用。SeriallInit()将环状缓冲区计数器的字节数清零,并初始化每个环状缓冲区的IN和OUT指针,指向数据存储区的开始处。数据接收信号量初始化为0,表示在环状缓冲区无数据。用传送缓冲区大小初始化数据传送信号量,表示缓冲区已空。
SerialIsEmpty()答应应用程序确定是否有字节从串口接收进来。本函数答应在无数据时避免将任务挂起。
SerialIsFull()答应应用程序确定传送环状缓冲区的状态,本函数可以在缓冲区已满时避免将任务挂起。
SerialPutChar()答应应用程序向一个串行端口发送数据。 http://www.armforum.cn


结束语:
该串口通信模块充分利用了实时内核的任务调度功能和信号量机制,系统软件模块化,可读性增强,便于修改和移植,其设计思路和方法可以很好的应用在多种情况下的测控系统中,系统的扩展方便,具有一定的借鉴作用。该系统已应用于洪水报警中!

系统分类: ARM
用户分类: ARM
标签: 无标签
来源: 转贴
发表评论 阅读全文(104) | 回复(0)

2

关于投票
关于μC/OS—II的串口通信模块设计(1)

 来源:ARM开发论坛

通常在嵌入式应用中,使用RTOS的主要原因是为了提高系统的可靠性,其次是提高开发效率、缩短开发周期。μC/OS-II是一个占先式实时多任务内核,使用对象是嵌入式系统,对源代码适当裁减,很轻易移植到8~32位不同框架的微处理器上。但μC/OS-II仅是一个实时内核,它不像其他实时操作系统(如嵌入式Linux)那样提供给用户一些API函数接口。在μC/OS-II实时内核下,对外设的访问接口没有统一完善,有很多工作需要用户自己去完成。串口通信是单片机测控系统的重要组成部分,异步串行口是一个比较简单又很具代表性的中断驱动外设。本文以单片机中的串口为例,介绍μC/OS—II下编写中断服务程序以及外设驅动程序的一般思路。

http://www.armforum.cn

  μC/OS-II的中断处理及51系列单片机中断系统分析
μC/OS-II中断服务程序(ISR)一般用汇编语言编写。以下是中断服务程序的步骤。保存全部CPU寄存器;
调用OSIntEnter()或OSIntNesting(全局变量)直接加1;
执行用户代码做中断服务;调用0SIntExit();
恢复所有CPU寄存器;
执行中断返回指令。
μC/OS-II提供两个ISR与内核接口函数;OSIntEnter()和OSIntExit()。OSIntEnter()通知μC/OS—II核,中断服务程序开始了。事实上,此函数做的工作是把一个全局变量OSIntNesting加1,此中断嵌套计数器可以确保所有中断处理完成后再做任务调度。另一个接口函数OSIntExit()则通知内核,中断服务已结束。根据相应情况,退回被中断点(可能是一个任务或者是被嵌套的中断服务程序)或由内核作任务调度。
用户编写的ISR必须被安装到某一位置,以便中断发生后,CPU根据相应的中断号运行准确的服务程序。许多实时操作系统都提供了安装和卸载中断服务程序的API接口函数,但μC/OS—II内核没有提供类似的接口函数,需要用户在对CPU的移植中自己实现。这些接口函数与具体的硬件环境有关,接下来以51单片机下的中断处理对此具体说明。 http://www.armforum.cn
51单片机的中断基本过程如下:CPU在每个机器周期的S5P2时刻采样中断标志,而在下一指令周期将对采样的中断进行查询。假如有中断请求,则按照优先级高低的原则进行处理。响应中断时,先置相应的优先级激活触发器于相应位,封锁同级或低级中断,然后根据中断源类别,在硬件控制下,将中断地址压入堆栈,并转向相应的中断向量入口单元。通常在入口单元处放一跳转指令,转向执行中断服务程序.当执行中断返回指令RETI时,把响应中断时所置位的优先级激活触发器清零后,从堆栈中弹
出被保护的断点地址,装入程序计数器PC,CPU返回原来被中断处继续执行程序。
在移植的过程中,采用Keil C51作为编译环境。KeilC5l集成C编译和汇编器。中断子程序用汇编语言编写,放到移植μC/0S—II后的OS_CPU_A.ASM汇编文件中。下面是以串行口中断为例的移植中断服务子程序代码。
CSEGAT0023H ;串口中断响应入口地址
LJMPSerialISR;转移到串口中断子程序入口地址
RSEG?PR?SeriallSR?OS_CPU_A
SerialISR:
USINGO
CLR EA ;先关中断,以防中断嵌套
PUSHALL ;已定义的压栈宏,用于将
;CPU寄存器的值压入堆栈
LCALL_?OSIntEnter ;监视中断嵌套
LCALL_?Serial ;串口中断服务程序

字串5


LCALL_?OSintExlt
SETBEA
POPALL;已定义的出栈宏,将CPU寄存器的值出栈
RETI ARM


2 串口驱动程序
笔者已在5l单片机上成功移植了μC/0S-II内核,移植过程在此不再讨论。这里重点分析μC/0S—II内核下串口驱动程序编写。
由于串行设备存在外设处理速度和CPU速度不匹配的问题,所以需要一个缓冲区.向串口发送数据时,只要把数据写到缓冲区中,然后由串口逐个取出往外发。从串口接收数据时,往往等收到若干个字节后才需要CPU进行处理,所以这些预收的数据可以先存于缓冲区中。实际上,单片机的异步串口中只有两个相互独立、地址相同的接收、发送缓冲寄存器SBUF。在实际应用中,需要从内存中开辟两个缓冲区,分别为接收缓冲区和发送缓冲区。这里把缓冲区定义为环形队列的数据结构。
μC/OS-II内核提供了信号量作为通信和同步的机制,引入数据接收信号量、数据发送信号量分别对缓冲区两端的操作进行同步。串口的操作模式如下:用户任务想写,但缓冲区满时,在信号量上睡眠,让CPU运行别的任务,待ISR从缓冲区读走数据后唤醒此睡眠的任务;同样,用户任务想读,但缓冲区空时,也可以在信号量上睡眠,待外部设备有数据来了再唤醒。由于μC/OS-II的信号量提供了超时等待机制,串口当然也具有超时读写能力。
图1是带缓冲区和信号量的串口接收示意图。数据接收信号量初始化为0,表示在环形缓冲区中无数据。 ARM
ARM

M开发论坛

接收中断到来后,ISR从UART的接收缓冲器SBUF中读入接收的字节(②),放入接收缓冲区(③),然后通过接收信号量唤醒用户任务端的读操作(④、①)。在整个过程中,可以查询记录缓冲区中当前字节数的变量值,此变量表明接收缓冲区是否已满。UART收到数据并触发了接收中断,但假如此时缓冲区是满的,那么放弃收到的字符。缓冲区的大小应合理设置,降低数据丢失的可能性,又要避免存储空间的浪费。
图2为带环形缓冲区和超时信号量的串口发送示意图。发送信号量初始值设为发送缓冲区的大小,表示缓冲区已空,并且关闭发送中断。发送数据时,用户任务在信号量上等待(①)。假如发送缓冲区未满,用户任务向发送缓冲区中写入数据(②)。假如写入的是发送缓冲区中的第一个字节,则答应发送中断(②)。然后,发送ISR从发送缓冲区中取出最早写入的字节输出至UART(④),这个操作又触发了下一次的发送中断,如此循环直到发送缓冲区中最后一个字节被取走,重新关闭发送中断。在ISR向UART输出的同时,给信号量发信号(⑤),发送任务据此信号量计数值来了解发送缓冲区中是否有空间。 ARM

系统分类: ARM
用户分类: ARM
标签: 无标签
来源: 转贴
发表评论 阅读全文(166) | 回复(0)

2

关于投票
LPC2000内部flash用作EEPROM详解

 来源:ARM开发者论坛

1. LPC2000的Flash简介
 LPC2000的Flash存储器系统包含128kB Flash器件的16个扇区和256kB Flash器件的17个扇区。Flash存储器从地址0开始并向上增加。Flash boot装载程序同时提供片内Flash存储器的ISP和IAP编程接口。IAP、ISP和RealMonitor程序都位于boot扇区。boot扇区存在于所有的器件当中。ISP和IAP命令不答应对boot扇区执行写/擦除/运行操作。在128kB Flash器件中只有120kB Flash可供用户程序使用。器件共包含256kB的Flash,其中,248kB的Flash可供用户程序使用。Boot Block一般位于片内Flash存储器顶端。在128kB Flash中,它是第16个扇区(对应的扇区号是15),在256kB Flash中,它是第18个扇区(对应的扇区号是17)。Boot Block占有的Flash存储器扇区不能用来存放用户数据。
LPC2000系列提供在在应用中编程IAP,最终用户代码直接执行在应用编程 (IAP)对片内Flash存储器进行擦除和编程操作。Falsh可以擦写10000次,512字节行编程时间为1ms。单扇区或整片擦除时间为400ms。
Flash存储器在写或擦除操作过程中不可被访问。
执行Flash写/擦除操作的IAP命令使用片内RAM顶端的32个字节空间。假如应用程序中答应IAP编程,那么用户程序不应使用该空间。 字串8
很多8位单片机中有页的概念,页为Flash编程的最小单位,每次可以擦除和编程一个页的内容,由于页中包含的字节较少,在这种情况下把Flash用作EEPROM灵活性会很好。而LPC2000系列没有页的概念,它只有扇区这个最小的Flash编程单位,即用户即使是只修改一个字节,也需要首先擦除8K的Flash。
把Flash当作EEPROM的过程,其实就是对Flash进行读-修改-写的过程。
2. 向Flash中写数据
Flash必须遵循选择扇区,擦除,选择扇区,写的过程,具体到程序的编写,必须先后有下面的代码:
SelSector(1,1); // 选择扇区1
EraseSector(1,1); // 擦除扇区1
SelSector(1,1); // 选择扇区1
for(i=0;i<512;i )
source[i]=0x41;
RamToFlash(0x00002000, (uint32)source, 512); // 写数据到扇区1
应用的时候需要注重下面几点:
1)假如写之前没有选择扇区,是不能正确写入的。
2)假如写之前没有擦除,写入是不正确的。
3)最少写512字节,写入的字节数应当为512 或 1024 或 4096 或 8192.
4)Flash在擦写时不能访问,这也是IAP是要关闭中断的原因。关中断可以用下面的语句来实现:__asm{MSR CPSR_c, #0xdf},与此对应,开中断可以下面的语句:__asm{MSR CPSR_c, #0x5f}。 M开发论坛
另外,经常有人问如何将一个常量的数值定义在Flash的特定地址上,我觉得这个功能不太实用,因为每次擦除的最小单位是8K,到不如直接写数据到Flash的一个地址,这个地址是在一个空扇区中,读和写都以这个地址为基址。由于编译后的代码是向下靠紧的,所以你可以查看一下编译后的代码量,然后选择靠上的地址做为用的变量区。假如实在想把数组定义在Flash的特定位置似乎可以用分散加载,具体可以参考zlg的FAQ的第378问。
3. 从Flash中读数据
从Flash中读数据比较简单,可以定义一个指针变量,该指针变量指向特定的Flash地址,例如可以写成下面的样子:
uint32 i;
uint8 * p;
p=(uint8 *)0x1C000;
for(i=0;i<400;i )
{
Puthexbyte(*(p ));
}
4. Flash的加密
代码读保护 这是Bootloader修订版1.61的特性。 代码读保护通过向Flash地址单元0x1FC(用户Flash扇区0)写入0x87654321(十进制表示为2271560481)来使能。地址单元0x1FC用来答应为fiq异常处理程序保留部分空间。当JTAG调试端口的代码读保护被使能时,外部存储器引导和以下ISP命令将被禁能:
&#61548; 读存储器
&#61548; 写RAM
&#61548; 运行
&#61548; 将RAM内容复制到Flash

ARM

上述ISP命令终止时返回CODE_READ_PROTECTION_ENABLED。 代码读保护使能时,ISP擦除命令只答应擦除用户扇区的内容。这种限制是代码读保护不使能时所没有的。IAP命令不受代码读保护的影响。
采用工程模板的RelInFlash会自动加密。
5. 采用工程模板时需要注重的地方
采用ZLG的工程模板时需要注重下面几点:
1)修改堆栈,在STARTUP.S文件中的初始化堆栈为 StackUsr-20*4
2)设置编译参数-apcs/intervork,需要注重是修改 Language Settings/ARM C Compiler/ATPS下面的。我一开始的时候不小心选择的语言设置是ARM Assembler ,结果运行程序后一写Flash就错,大家要选准语言设置。
3)变量定义,由于一次至少写512个字节,所以跟读写操作的变量最好定义为uint32类型的,我犯的一个错误是将变量定义为uint8类型的,如下面:
uint8 i;
for(i=0;i<512;i )
source[i]=0x41;
RamToFlash(0x00002000, (uint32)source, 512); // 写数据到扇区1
最后的结果可想而知,一直在for循环中运行而跳不出来,这就给了我们一个IAP不好用的假象。所以必须注意!
系统分类: 虚拟仪器
用户分类: ARM
标签: 无标签
来源: 转贴
发表评论 阅读全文(127) | 回复(0)
总共 , 当前 /