引言
MCS51系列单片机应用广泛,在我国学习研究的人较多。使用C语言在单片机上开发程序可提高开发效率,目前针对该内核兼容单片机开发的C语言编译器有Keil、Tasking、Raisonance、IAR和HiTech等,但这些都是商业化的产品,使用需要付费购买。使用专为单片机开发的免费C语言编译器SDCC(Small Device C Compiler)则是一个不错的选择。
由于技术和工艺的发展,各种MCS51系列内核兼容的新型单片机不断推出,除了运行速度提高,内部资源也逐渐丰富。例如,Silicon Labs公司推出的C8051F系列单片机,兼容8051内核,功能强大,运算速度快,处理能力强,为复杂软件的运行提供了可能。
本文介绍了SDCC编译器和FreeRTOS实时操作系统,在C8051F340上移植了FreeRTOS并使用SDCC编译开发了门禁系统。事实证明,使用免费的资源完全可以满足某些系统的开发需求。
1 SDCC编译器和FreeRTOS简介
SDCC是Sandeep Dutta为8位微控制器设计的一个开放源代码、可编译产生不同CPU的目标代码、优化的ANSIC编译器。当前版本的目标CPU是Intel公司的MCS51兼容系列微处理器芯片、Dallas公司的DS80C390系列、Freescale公司的HC08系列、Microchip公司的PIC系列和Atmel公司的AVR系列等。SDCC编译器的代码遵循GPL协议发布,可以免费使用。
FreeRTOS是为小型嵌入式系统开发的一个开放源代码、免费的实时操作系统内核。其内核大部分使用C语言编程,具有高度的可移植性,目前已经被移植到的处理器平台超过19种。FreeRTOS操作系统商业应用免费,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。FreeRTOS提供的功能包括任务管理、时间管理、信号量、消息队列、内存管理等功能,可基本满足较小系统的需要。
2 FreeRTOS在C8051F340中的移植和调试
FreeRTOS设计时就考虑了在各种平台上的可移植性,内核大部分代码使用C语言编写,少数代码使用相应平台的汇编语言编写并且这部分被压缩到最小。FreeRTOS已经被移植到各种微控制器上,在8051平台上也有相应的移植代码。从FreeRTOS网站下载得到的程序中,包含了一个在C8051F120单片机上的移植版本。
C8051F120和C8051F340单片机在硬件资源上的主要差别,如表1所列。
表1 C8051F120和C8051F340的硬件资源比较
FreeRTOS对目标平台硬件资源的要求不高,最后编译的目标代码量由所选配置选项决定。一般需要2 KB RAM和10 KB左右的ROM即可运行。由表1可以看出,二者的硬件平台比较接近,因此移植工作量不大。
针对C8051F120和C8051F340单片机硬件平台的差别,将在C8051F120单片机上运行的FreeRTOS移植到C8051F340平台上所做的工作包括: 替换C8051F120 CPU的头文件,调整RAM范围大小,修改外部晶振频率,修改时钟滴答数等。修改的文件有FreeRTOSDemoCygnalFreeRTOSConfig.h和FreeRTOSSourceportableSDCCCygnalport.c。
FreeRTOSConfig.h修改后的文件主要内容如下:
/*包含在SDCC中的C8051F340头文件*/
#include "c8051f340.h"
/* CPU晶振频率,时钟滴答数等 */
#define configCPU_CLOCK_HZ (( unsigned portLONG)12000000)
#define configTICK_RATE_HZ (( portTickType )100 )
#define configMAX_PRIORITIES (( unsigned portBASE_TYPE )4 )
#define configMINIMAL_STACK_SIZE
((unsigned port
SHORT)200(unsigned portSHORT)configSTACK_START)
/*RAM使用修改为3×1024 */
#define configTOTAL_HEAP_SIZE ((size_t)(3 * 1024))
/*FreeRTOS系统函数配置,1为使用这个功能,0则不使用*/
#define INCLUDE_vTaskPrioritySet 0
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend0
#define INCLUDE_vTaskDelayUntil 0
#define INCLUDE_vTaskDelay 1
FreeRTOS的C8051F120平台移植代码中使用定时器2来产生系统所需的定时中断。C8051F340和C8051F120的定时器2寄存器配置略有不同,port.c中的static void prvSetupTimerInterrupt( void )函数修改后内容如下:
static void prvSetupTimerInterrupt(void) {
const unsigned portLONG ulTicksPerSecond = configCPU_CLOCK_HZ / portCLOCK_DIVISOR;
const unsigned portLONG ulCaptureTime = ulTicksPerSecond / configTICK_RATE_HZ;
const unsigned portLONG ulCaptureValue = portMAX_TIMER_VALUE ulCaptureTime;
const unsigned portCHAR ucLowCaptureByte=(unsigned portCHAR ) ( ulCaptureValue & ( unsigned portLONG ) 0xff );
const unsigned portCHAR ucHighCaptureByte=(unsigned portCHAR ) ( ulCaptureValue >> ( unsigned portLONG ) 8);
/*定时器2计数器初始值*/
TMR2RLL = ucLowCaptureByte;
TMR2RLH = ucHighCaptureByte;
/*
定时器2计数器重装值*/
TMR2L = ucLowCaptureByte;
TMR2H = ucHighCaptureByte;
/*使能定时器2中断*/
IE |= portTIMER_2_INTERRUPT_ENABLE;
/*启动定时器2*/
TMR2CN = portENABLE_TIMER;
}
Silicon Labs公司提供了一个集成开发环境(IDE),可方便地使用该IDE开发C8051F系列单片机程序。该IDE支持多种第三方编译工具,如Keil、Raisonance、Tasking、HiTech、SDCC和IAR等,使用时只需安装对应的软件,然后设置编译器的安装路径和编译选项即可,如图1所示。本文只对涉及SDCC的选项进行说明。
图1 Silicon Labs的集成开发环境编译器设置方式
SDCC可从http://sdcc.sourceforge.net下载得到。本文使用的版本为sdccwin32 2.8.0,具体安装方法和步骤参考sdccman.pdf手册。安装完后,在C8051F340平台上编译FreeRTOS的SDCC选项,如表2所列。
表2 C8051F340平台上编译FreeRTOS的SDCC选项
Assembler 、Compiler和Linker选项的功能主要是: 指定编译时的编译模式、堆栈设定方式、函数库的编译模式、单片机XRAM大小,指定包含头文件路径等。
另外需要注意的是,SDCC在Windows操作系统上默认安装文件中不包含大模式下的库,需要重新利用SDCC的源码编译得到,然后在SDCC的安装目录下建立/lib/largestackauto目录,将编译生成的库文件添加到此。有关SDCC的安装和相关编译选项的详细信息,请参考SDCC的说明手册。
编译环境设置完毕后,将FreeRTOS源码包中croutine.c、list.c、queue.c、tasks.c和新建的文件main.c添加到IDE中,并进行编译。如果没有警告和错误提示,表明编译成功,可在IDE的Out put window中看到编译的输出信息,如图2所示。
图2 在Silicon Labs IDE中使用SDCC调试FreeRTOS
编译成功后,即可将目标代码下载到单片机中调试运行。调试时需注意,一定要先关闭C8051F340的内部看门狗,否则单片机上电后未执行到main()函数之前,看门狗定时器便溢出,使得单片机复位导致调试无法进行下去。解决方法是编写一个函数_sdcc_external_startup()并添加关闭看门狗的代码,SDCC编译器编译后,单片机上电后会首先执行这个函数,关掉看门狗。添加的_sdcc_external_startup()代码如下:
void _sdcc_external_startup (void) {
PCA0MD &= ~0x40;
/*关闭C8051F340的内部看门狗*/
}
3 在门禁系统中使用FreeRTOS
FreeRTOS移植完成后,成功地在开发的门禁系统中得到了应用验证。该门禁系统实现的功能主要有: 实现刷ID卡开门,利用键盘输入住户号和密码开门,住户数据使用GPRS服务通信实现数据远程管理等。
硬件系统主要由C8051F340单片机、ID卡读卡模块、GPRS模块、键盘/显示模块和存储器模块等组成,系统结构如图3所示。
图3 门禁系统主要硬件组成
系统软件上如果使用传统的前后台程序设计思路,则程序结构复杂,设计周期长,测试困难。使用实时操作系统,可将系统按功能和设备依赖性的原则划分为不同的任务,各个任务可以看作是并行执行,任务之间使用实时操作系统提供的API实现存储器互斥访问和其他资源的同步等,可以较好地满足该系统的需求。
根据系统的功能,建立3个任务:ID卡读卡处理任务、键盘/显示任务和GPRS数据通信处理任务。各个任务的功能如下:
① ID卡读卡处理任务 vIdTask。
ID卡读卡任务主要完成ID卡卡号的读取和识别等功能,优先级最高。
② 键盘/显示任务 vKeyDispTask。
键盘/显示模块主要完成人机交互和日期的显示,错误信息的提示等,优先级次之。
③ GPRS数据通信处理任务 vGPRSTask。
GPRS数据通信任务主要完成与管理端GPRS模块的通信连接和GPRS协议数据的处理等,优先级最低。
另外,GPRS模块使用串行通信口与C8051F340通信,串口的接收程序采用中断服务程序,不受操作系统的管理。当收到对应的信息时,向GPRS数据通信处理任务发送消息,GPRS数据通信处理任务再进行处理。建立的三个任务都有可能同时读写存储器,因此建立一个互斥信号量,当需要操作存储器时,先得到这个信号量,存储器操作完毕后再释放这个信号量。ID卡读卡处理任务的代码中互斥信号量的使用如下:
void vIdTask( void *pvParameters ) {
……
while(1) {
/*如果检测到ID卡*/
if( detect_id()==TRUE ) {
……
if(xSemaphoreTake(xSemaphore,50)==pdTRUE) {
/*如果得到存储器操作的互斥信号量,则处理*/
id_card_process();
/*操作完毕释放存储器信号量*/
xSemaphoreGive( xSemaphore );
}
else {
/*没有得到存储器操作的互斥信号量*/
……
}
}
vTaskDelay(3);
}
}
系统主函数主要完成硬件初始化,建立信号量、任务和各个任务的启动等。部分代码实现如下:
xSemaphoreHandle xMemMutSem;//存储器操作的互斥信号量
void main( void ) {
hardware_init();/*硬件初始化*/
misc_init();/*其他初始化*/
SIM300C_init(); /*GPRS模块初始化*/
……/*建立存储器操作的互斥信号量等*/
xMemMutSem=xSemaphoreCreateMutex();
/*建立任务*/
xTaskCreate(vIdTask,"IdTask",100,NULL,3,NULL);
xTaskCreate(vKeyDispTask,"KeyDisp",150,NULL,2,NULL);
xTaskCreate(vGPRSTask,"GPRSTask",300,NULL,1,NULL);
/*启动任务*/
vTaskStartScheduler();
}
4 结论
使用SDCC编译器和FreeRTOS操作系统等免费资源开发系统程序,能够减少工作量,降低开发成本,具有很大的优势。SDCC编译器应用灵活,配置方便,FreeRTOS经过修改裁减后,代码精简,结构紧凑,适合于小型嵌入式系统应用。作者在门禁系统中应用得到成功的验证;但是SDCC和FreeRTOS仍有许多缺点,如SDCC没有IDE,编译配置选项复杂,FreeRTOS提供的服务功能有限等。