嵌入式系统课程设计报告.docx
《嵌入式系统课程设计报告.docx》由会员分享,可在线阅读,更多相关《嵌入式系统课程设计报告.docx(16页珍藏版)》请在冰豆网上搜索。
嵌入式系统课程设计报告
NORTHCHINAUNIVERSITYOFSCIENCEANDTECHNOLOGY
嵌入式系统课程设计报告
学生姓名:
学号:
学院:
专业班级:
指导教师:
同组成员:
2016年12月26日
一、课程设计目的
本课程设计是在《嵌入式系统原理与应用》课程的基础上,通过软件编程及仿真调试的实践,进一步掌握嵌入式系统的原理和应用方法,是毕业设计前的一次重要实践,为今后从事嵌入式系统相关工作岗位打下良好的基础。
二、设计题目及要求
2.1设计题目:
基于STM32和uC/OS-II的多任务设计
2.2功能实现:
使用uC/OS-II的任务管理函数和STM32库函数控制相应的寄存器,完成一个多任务设计。
整个设计共有4个任务,驱动一个LED指示灯闪烁、由3个LED指示灯组成的流水灯、驱动蜂鸣器和利用swd方式进行printf输出。
2.3设计要求:
理解和熟练使用KEIL软件、STM32寄存器、STM32库函数和uC/OS-II任务管理函数,用KEIL软件完成编程和调试,下载到开发板中实现4个设定的任务,并完成课程设计报告。
四个任务分别为:
(1)驱动1个LED指示灯闪烁、
(2)由3个LED指示灯组成流水灯
(3)驱动蜂鸣器发出响声。
(4)利用swd方式进行printf输出。
三、设计原理说明
3.1硬件说明
本次课程设计主要使用的是STM32神舟IV号开发板为基础进行课程设计的,本节将详细介绍神舟IV号开发板的各部分硬件原理与实现。
(1)开发板资源图
(2)MCU
开发板的处理器是STM32F107VCT6,该处理器基于ARMV7架构的Cortex-M3内核,主频72Mhz,内部含有256K字节的FLASH和64K字节的SRAM,LQFP100封装。
(3)蜂鸣器
开发板板载一个无源蜂鸣器,用于产品告警或声音提醒。
蜂鸣器连接到了处理器的PA3管脚,当处理器的PA3管脚输出低电平时蜂鸣器开始鸣响,反之处理器的PA3管脚输出高电平时蜂鸣器停止鸣响.
(4)指示灯
开发板提供了1个电源指示灯和4路通用LED指示灯。
电源指示灯指示3.3V电源是否正常。
4路通用LED指示灯可以用于指示STM32开发板的状态。
用户LED指示灯由GPIO管脚控制LED灯的亮灭,当GPIO管脚输出低电平时,LED指示灯亮。
反之,当GPIO管脚输出高电平时,LED指示灯灭。
这四个LED指示灯分别由PD2、PD3、PD4和PD7控制。
(5)JTAG仿真调试
开发板提供标准的20针JTAG接口,可以直接和JLINKV8仿真器连接,下载程序,调试仿真;
(6)晶振电路
STM32F107内部已经包含了8MHz高速内部RC振荡电路,但是其精准度不是很高;为此在外部增加了25MHz的晶振电路,为系统的可靠工作提供时序基准。
(7)设计中用到的管脚
芯片引脚
开发板模块
PD2
LED1
PD3
LED2
PD4
LED3
PD7
LED4
PA3
蜂鸣器
3.2STM32寄存器使用说明
设计中,只用到时钟和GPIO相关的寄存器。
(1)STM32F107VC中共有80个GPIO,分成A、B、C、D、E五个组,每组有13-16个可用的I/O端口,每个GPIO可以自由编程。
通过各个寄存器来控制GPIO输出高电平或者是低电平。
每个GPIO有7个寄存器来控制,其中CRL和CRH用来确定I/O管脚的方向和速率以及何种驱动方式,BSRR可直接修改某一个CPIO引脚的高低电平,BRR可将GPIO置零。
(2)在使用配置GPIO寄存器之前,都要先配置GPIO的时钟。
通过RCC寄存器当中的CR、CFGR和CIR来设置系统时钟。
GPIO挂在APB2总线上,可对APB2ENR寄存器设置来确定所用到的GPIO时钟。
(3)μC/OS-II用Cortex-M3的SysTick定时器产生操作系统需要的滴答时钟,作为整个系统的根基。
SysTick定时器的四个寄存器SysTick_CTRL、SysTick_LOAD、SysTick_VAL、SysTick_CALIB控制每隔一定时间产生一个中断使μC/OS-II系统能进行多任务控制。
(3)用到的寄存器:
CRL、CRH、BRR、BSRR、CR、CFGR、CIR、APB2ENR、SysTICK_CTRL、SysTICK_LOAD、SysTICK_VAL、SysTICK_CALIB
3.3STM32库函数使用说明
设计中只用到时钟和GPIO相关的库函数。
(1)直接配置寄存器开发,如果代码比较庞大,可读性差。
ST针对STM32封装好一个软件封装库,开发者可调用函数接口(API,ApplicationProgramInterface)来完成相应的开发工作,配置寄存器的工作由接口函数完成,使开发人员脱离最底层的寄存器操作,易于阅读,维护成本低。
库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为用户提供配置寄存器的接口。
库开发方式与直接配置寄存器的方式的区别:
(2)库目录和文件简介
Libraries文件夹下是驱动库的源代码及启动文件。
在使用库开发时,需要把libraries目录下的相关库函数文件添加到工程中。
进入Libraries文件夹看到,关于内核与外设的库文件分别存放在CMSIS和STM32F10x_StdPeriph_Driver文件夹中。
CMSIS(CortexMicrocontrollerSoftwareInterfaceStandard):
ARM将所有Cortex芯片厂商的产品的软件接口标准化,制定了CMSIS标准。
CMSIS层起着承上启下的作用,一方面该层对硬件寄存器层进行了统一的实现,屏蔽了不同厂商对Cortex-M系列微处理器核内外设寄存器的不同定义,另一方面又向上层的操作系统和应用层提供接口,简化了应用程序开发的难度。
Libraries\CMSIS\CM3文件夹下又分为CoreSupport和DeviceSupport文件夹。
在CoreSupport中的是M3核通用的源文件core_cm3.c和头文件core_cm3.h,作用是为采用Cortex-M3核设计SOC的芯片商设计的芯片外设提供一个进入M3内核的接口。
这两个文件在其它公司的Cortex-M3系列芯片也是相同的。
我们只需把这个文件加进我们的工程文件即可。
在DeviceSupport文件夹下的是启动文件、外设寄存器定义&中断向量定义层的一些文件,由ST公司提供。
system_stm32f10x.c文件的功能是设置系统时钟和总线时钟,该文件中包含了stm32f10x.h这个头文件。
启动文件要选择startup_stm32f10x_cl.s。
系统启动文件由汇编编写,不同的文件对应不同的芯片型号。
启动文件是任何处理器在上电复位之后最先运行的一段汇编程序。
在我们编写的c语言代码运行之前,需要由汇编为c语言的运行建立一个合适的环境,接下来才能运行我们的程序。
所以我们也要把启动文件添加进我们的的工程中去,其作用相当于bootloader。
STM32F10x_StdPeriph_Driver:
该文件夹下有inc和src两个文件夹,都属于CMSIS的设备外设函数部分。
src里面是每个设备外设的驱动程序。
src和inc文件夹里的就是ST公司针对每个STM32外设而编写的库函数文件,每个外设对应一个.c和.h后缀的文件。
我们把这类外设文件统称为:
stm32f10x_ppp.c或stm32f10x_ppp.h文件,ppp表示外设名称。
如针对GPIO外设,在src文件夹下有一个stm32f10x_gpio.c源文件,在inc文件夹下有一个stm32f10x_gpio.h头文件,设计中用到了STM32的GPIO,则至少要把这两个文件包含到工程里。
这两个文件夹中,还有一个很特别的misc.c文件,这个文件提供了外设对内核中的NVIC(中断向量控制器)的访问函数,在配置中断时,我们必须把这个文件添加到工程中。
在用库建立一个完整的工程时,还需要添加user目录下的stm32f10x_it.c、stm32f10x_it.h、stm32f10x_conf.h这三个文件。
stm32f10x_it.c用来编写中断服务函数;stm32f10x_conf.h用来配置使用了什么外设的头文件,用这个头文件我们可以很方便地增加或删除外设驱动函数库。
库文件直接包含进工程即可,丝毫不用修改,而有的文件就要我们在使用的时候根据具体的需要进行配置。
(3)用到的库函数:
SystemInit、RCC_APB2PeriphClockCmd、SysTick_Config、GPIO_Init、GPIO_SetBits、GPIO_ResetBits。
3.4uC/OS-II任务管理函数使用说明
设计中用到的任务管理函数包括任务堆栈的建立、任务的创建和uC/OS-II的初始化和任务的启动。
(1)UCOSII的前身是UCOS,最早出自于1992年美国嵌入式系统专家JeanJ.Labrosse把UCOS的源码发布在BBS上。
目前最新的版本是UCOSIII,但是现在使用最为广泛的还是UCOSII。
UCOSII是一个可裁减的、抢占式、实时多任务内核,具有高度可移植性,特别适合于微处理器和控制器,已经移植到近40多种处理器体系上,涵盖了从8位到64位各种CPU(包括DSP)。
UCOSII(V2.91版本)体系结构如下图所示:
(2)uC/OS-II操作系统内核的主要工作就是对任务进行管理和调度,任务的执行代码通常是一个无限循环结构。
从程序设计的角度来看,一个uC/OS-II任务的代码就是一个C语言函数,任务的参数是一个void类型的指针,但是这些函数是由主函数main()来负责创建和启动,然后由操作系统负责调度和运行,而不是调用的关系。
OSTaskCreate()为创建任务的函数,OSStart()为启动任务的函数。
使用OSStart()之后,任务就交由操作系统来管理和调度。
每个任务都必须具有一个唯一的优先级别,每一个级别都用一个数字来表示,比如数字为0~255.
在存储器中按数据“后进先出”的原则组织的连续存储空间称为堆栈,为了满足任务切换和响应中断时保存CPU寄存器中的内容及存储任务私有数据的需要,每个任务都应该配有自己的堆栈。
任务堆栈是任务的重要组成部分。
使用数据类型OS_STK来定义任务堆栈,即定义一个OS_STK类型的数组。
在使用uC/OS-II的所有服务之前,必须调用uC/OS-II的初始化函数OSInit(),对uC/OS-II自身的运行环境进行初始化。
为了能使用习惯的方法来使任务延时,uC/OS-II提供了一个可以用时、分、秒为参数的任务延时函数OSTimeDlyHMSM(),比如延时1秒可用OSTimeDlyHMSM(0,0,0,1000).
(3)需要用到的任务管理函数:
OSInit、OSTaskCreate、OSStart、OSTimeDlyHMSM
四、软件设计
(含流程图、带注释的程序清单)
/*************
*main.c
**************/
#include"includes.h"
#include"stm32f10x.h"
#include"stm32f10x_rcc.h"
#include"stdio.h"
constuint32_tSystemFrequency=72000000;
#defineRCC_GPIO_LEDRCC_APB2Periph_GPIOD
#defineGPIO_LEDGPIOD
#defineDS1_PINGPIO_Pin_4
#defineITM_Port8(n)(*((volatileunsignedchar*)(0xE0000000+4*n)))
#defineITM_Port16(n)(*((volatileunsignedshort*)(0xE0000000+4*n)))
#defineITM_Port32(n)(*((volatileunsignedlong*)(0xE0000000+4*n)))
#defineDEMCR(*((volatileunsignedlong*)(0xE000EDFC)))
#defineTRCENA0x01000000
GPIO_InitTypeDefGPIO_InitStructure;
#defineTASK_1_PRIO5
#defineTASK_2_PRIO6
#defineTASK_3_PRIO7
#defineTASK_4_PRIO8
#defineTASK_1_STK_SIZE100
#defineTASK_2_STK_SIZE100
#defineTASK_3_STK_SIZE100
#defineTASK_4_STK_SIZE100
OS_STKtask_1_stk[TASK_1_STK_SIZE];//定义堆栈
OS_STKtask_2_stk[TASK_2_STK_SIZE];//定义堆栈
OS_STKtask_3_stk[TASK_3_STK_SIZE];//定义堆栈
OS_STKtask_4_stk[TASK_4_STK_SIZE];//定义堆栈
struct__FILE{inthandle;};
FILE__stdout;
FILE__stdin;
/**
*重写fputc函数
**/
intfputc(intch,FILE*f)
{
if(DEMCR&TRCENA)
{
while(ITM_Port32(0)==0);
ITM_Port8(0)=ch;
}
return(ch);
}
voidTask_1(void*arg)
{
while
(1)
{
GPIO_ResetBits(GPIO_LED,DS1_PIN);//点亮LED3
OSTimeDlyHMSM(0,0,0,1000);
GPIO_SetBits(GPIO_LED,DS1_PIN);//熄灭LED3
OSTimeDlyHMSM(0,0,0,1000);
}
}
voidTask_2(void*arg)
{
while
(1)
{
GPIO_ResetBits(GPIO_LED,GPIO_Pin_2);//点亮LED1
OSTimeDlyHMSM(0,0,0,1500);
GPIO_SetBits(GPIO_LED,GPIO_Pin_2);//熄灭LED1
GPIO_ResetBits(GPIO_LED,GPIO_Pin_3);//点亮LED2
OSTimeDlyHMSM(0,0,0,1500);
GPIO_SetBits(GPIO_LED,GPIO_Pin_3);//熄灭LED2
GPIO_ResetBits(GPIO_LED,GPIO_Pin_7);//点亮LED4
OSTimeDlyHMSM(0,0,0,1500);
GPIO_SetBits(GPIO_LED,GPIO_Pin_7);//熄灭LED4
}
}
voidTask_3(void*arg)
{
while
(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_3);//无源蜂鸣器响
OSTimeDlyHMSM(0,0,0,1000);
GPIO_SetBits(GPIOA,GPIO_Pin_3);//无源蜂鸣器不响
OSTimeDlyHMSM(0,0,0,1500);
}
}
voidTask_4(void*arg)
{
while
(1)
{
printf("hello,world!
\n");
}
}
intmain(void)
{
SystemInit();//配置系统时钟为72M
SysTick_Config(SystemFrequency/OS_TICKS_PER_SEC);//使能SysTick定时器
RCC_APB2PeriphClockCmd(RCC_GPIO_LED|RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA和GPIOD的时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIO_LED,&GPIO_InitStructure);//LED灯相关的GPIO初始化
GPIO_Init(GPIOA,&GPIO_InitStructure);//无源蜂鸣器相关的GPIO初始化
GPIO_SetBits(GPIO_LED,GPIO_Pin_All);//熄灭所有LED指示灯
GPIO_SetBits(GPIOA,GPIO_Pin_3);//让无源蜂鸣器不响
OSInit();//操作系统初始化
OSTaskCreate(Task_1,(void*)0,&task_1_stk[TASK_1_STK_SIZE-1],TASK_1_PRIO);//创建任务Task_1
OSTaskCreate(Task_2,(void*)0,&task_2_stk[TASK_2_STK_SIZE-1],TASK_2_PRIO);//创建任务Task_2
OSTaskCreate(Task_3,(void*)0,&task_3_stk[TASK_3_STK_SIZE-1],TASK_3_PRIO);//创建任务Task_3
OSTaskCreate(Task_4,(void*)0,&task_4_stk[TASK_4_STK_SIZE-1],TASK_4_PRIO);//创建任务Task_4
OSStart();//启动操作系统
}
/******************************************************************************/
/*STM32DBG.INI:
STM32DebuggerInitializationFile*/
/******************************************************************************/
//<<>>//
/******************************************************************************/
/*ThisfileispartoftheuVision/ARMdevelopmenttools.*/
/*Copyright(c)2005-2007KeilSoftware.Allrightsreserved.*/
/*Thissoftwaremayonlybeusedunderthetermsofavalid,current,*/
/*enduserlicencefromKEILforacompatibleversionofKEILsoftware*/
/*developmenttools.Nothingelsegivesyoutherighttousethissoftware.*/
/******************************************************************************/
FUNCvoidDebugSetup(void){
//DebugMCUConfiguration
//DBG_SLEEPDebugSleepMode
//DBG_STOPDebugStopMode
//DBG_STANDBYDebugStandbyMode
//TRACE_IOENTraceI/OEnable
//TRACE_MODETraceMode
//<0=>Asynchronous
//<1=>Synchronous:
TRACEDATASize1
//<2=>Synchronous:
TRACEDATASize2
//<3=>Synchronous:
TRACEDATASize4
//DBG_IWDG_STOPIndependantWatchdogStoppedwhenCoreishalted
//DBG_WWDG_STOPWindowWatchdogStoppedwhenCoreishalted
//DBG_TIM1_STOPTimer1StoppedwhenCoreishalted
//DBG_TIM2_STOPTimer2StoppedwhenCoreishalted
//DBG_TIM3_STOPTimer3StoppedwhenCoreishalted
//DBG_TIM4_STOPTimer4StoppedwhenCoreishalted
//DBG_CAN_STOPCANStoppedwhenCoreishalted
//
_WDWORD(0xE0042004,0x00000027);//DBGMCU_CR
_WDWORD(0xE000ED08,0x20000000);//SetupVectorTableOffsetRegister
}
DebugSetup();//DebuggerSetup
五、设计总结
本学期为期一周的嵌入式课程设计在不知不觉中结束了,虽说这次课程设计时间不是很长,但是感觉自己收获颇丰,不仅学习到了一些新知识,回顾了以前的一些快要遗忘的知识点,而且使自己的学习目标更加明确,学习方法更加