基于stm32f103zet6之UC/OS_II的学习1(初步移植OS--点灯大法)

很久很久都没有写博客了,最近真是比赛一个接着一个,都需要参加,所以stm32的学习一直停滞不前,趁着最近准备模块的时间开始着手ucosII的学习,

没办法呀,学习还是要继续的。。

现在开始正式学习,今天的要求不高,只是分析一下移植的时候需要注意的问题,暂且不研究内核代码!(代码移植参照着ST官方源代码)

也就是资源里面名为 取AN-1018.pdf的文档。

代码这里可以下载http://download.csdn.net/detail/king_bingge/5353528

一、uc/OS的实时性是靠什么实现的?

1、uC/OS的实时性就是靠定时中断来完成。

2、每个时钟节拍到来,就会产生一次定时中断,中断后进行任务调度,运行就绪表中优先级最高的任务(非抢先型内核中断后继续运行被中断任务)。

即过一段时间就检测是否有重要任务需要运行,是的就转而运行更重要的任务,从而确保实时性(裸机程序就无法这样做了)。

当然这里没有把系统调用考虑进去。

二、首先整体把握一下在M3上运行ucosII的架构


这就是整个系统各模块之间的关系,好的接下来就按照手册来分析一下移植的时候需要注意的地方

1、关于OS_CPU.h文件

#ifndef  OS_CPU_H
#define  OS_CPU_H


#ifdef   OS_CPU_GLOBALS
#define  OS_CPU_EXT
#else
#define  OS_CPU_EXT  extern
#endif

一个全局变量的声明问题

2、类型定义

typedef unsigned char  BOOLEAN;
typedef unsigned char  INT8U;                    /* Unsigned  8 bit quantity                           */
typedef signed   char  INT8S;                    /* Signed    8 bit quantity                           */
typedef unsigned short INT16U;                   /* Unsigned 16 bit quantity                           */
typedef signed   short INT16S;                   /* Signed   16 bit quantity                           */
typedef unsigned int   INT32U;                   /* Unsigned 32 bit quantity                           */
typedef signed   int   INT32S;                   /* Signed   32 bit quantity                           */
typedef float          FP32;                     /* Single precision floating point                    */
typedef double         FP64;                     /* Double precision floating point                    */

typedef unsigned int   OS_STK;                   /* Each stack entry is 32-bit wide                    */
typedef unsigned int   OS_CPU_SR;                /* Define size of CPU status register (PSR = 32 bits) */
对于常用的编译器,这些都是没有问题的

3、接下来是两个比较重要的函数,在汇编代码里面

#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
这两个代码就是进入和退出临界区的两个宏。所以当你使用了这两个宏定义,那么就需要加上这一句OS_CPU_SR  cpu_sr = 0;  进行定义并且初始化。

所谓临界区:是指一些不能被中断的代码。哪些代码是不能中断的呢,比如我们模拟的入栈操作,再比如当我们在执行系统调用的时候。那么类似于这钟代码就是临界区,而上面这两个宏的作用就是当某些代码为临界代码的时候,那么我们就在开始这段代码的时候加上ENTER宏,在退出这段代码的时候就加上EXIT宏。

4、接下来继续看看这两个宏做了什么事情吧

跟踪进去可以发现

OS_CPU_SR_Save
    MRS     R0, PRIMASK                                         ; Set prio int mask to mask all (except faults)
    CPSID   I
    BX      LR

OS_CPU_SR_Restore
    MSR     PRIMASK, R0
    BX      LR

就是我们上一步所说的打开和屏蔽中断,注意了,根据ATCPS规则(不知道的可以百度),C和汇编进行混合调用的时候,R0传递着第一个参数,并且R0还是传递返回值的。

5、接下来就是栈的增长方向,在我们的stm32板子上面,栈是向下增长的,堆是向上增长的

#define  OS_STK_GROWTH        1                   /* Stack grows from HIGH to LOW memory on ARM        */

#define  OS_TASK_SW()         OSCtxSw()

第二个宏定义是任务切换的宏,下面会提到

6、下面涉及到得就是这个文件里面需要修改的代码,首先看源代码,这是函数原型声明

/*
*********************************************************************************************************
*                                              PROTOTYPES
*********************************************************************************************************
*/

#if OS_CRITICAL_METHOD == 3                       /* See OS_CPU_A.ASM                                  */
OS_CPU_SR  OS_CPU_SR_Save(void);
void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif

void       OSCtxSw(void);
void       OSIntCtxSw(void);
void       OSStartHighRdy(void);

void       OS_CPU_PendSVHandler(void);

                                                  /* See OS_CPU_C.C                                    */
void       OS_CPU_SysTickHandler(void);
void       OS_CPU_SysTickInit(void);

                                                  /* See BSP.C                                         */
INT32U     OS_CPU_SysTickClkFreq(void);

我们需要做的就是把这个三个函数注释掉,因为这是我们自己实现的

                                                  /* See OS_CPU_C.C                                    */
// void       OS_CPU_SysTickHandler(void);
// void       OS_CPU_SysTickInit(void);

//                                                   /* See BSP.C                                         */
// INT32U     OS_CPU_SysTickClkFreq(void);
至此,第一个文件修改完毕,继续。。

三、关于os_cfg.h文件

1、这里都是一些配置,根据我们需要实现的功能来配置我们的OS,当然,如果只是为了点灯,那么我们可以这样做

 #define OS_FLAG_EN                    0   //禁用信号量集    
 #define OS_MBOX_EN                   0   //禁用邮箱    
 #define OS_MEM_EN                     0   //禁用内存管理    
 #define OS_MUTEX_EN                0   //禁用互斥信号量    
 #define OS_Q_EN                        0   //禁用队列    
 #define OS_SEM_EN                     0   //禁用信号量    
 #define OS_TMR_EN                     0   //禁用定时器    
 #define OS_DEBUG_EN               0   //禁用调试  
 
 #define OS_APP_HOOKS_EN           0    336. #define OS_FLAG_EN                0   //禁用信号量集    
 #define OS_MBOX_EN                0   //禁用邮箱    
#define OS_MEM_EN                 0   //禁用内存管理    
#define OS_MUTEX_EN               0   //禁用互斥信号量    
 #define OS_Q_EN                   0   //禁用队列    
#define OS_SEM_EN                 0   //禁用信号量    
 #define OS_TMR_EN                 0   //禁用定时器    
 #define OS_DEBUG_EN               0   //禁用调试  
 #define OS_APP_HOOKS_EN           0    //hook函数也可以注释掉
 #define OS_EVENT_MULTI_EN         0  //多重事件函数也是一样
 #define OS_EVENT_MULTI_EN         0  

那么,到这里,这个文件中需要修改的内容就是这么多了。

四、关于os_cpu_c.c文件。

这个文件是对应于之前的宏开关来说的,我们要把之前三个函数相关的宏开关以及函数的定义注释掉,具体操作如下

// #define  OS_CPU_CM3_NVIC_ST_CTRL    (*((volatile INT32U *)0xE000E010))   /* SysTick Ctrl & Status Reg. */
// #define  OS_CPU_CM3_NVIC_ST_RELOAD  (*((volatile INT32U *)0xE000E014))   /* SysTick Reload  Value Reg. */
// #define  OS_CPU_CM3_NVIC_ST_CURRENT (*((volatile INT32U *)0xE000E018))   /* SysTick Current Value Reg. */
// #define  OS_CPU_CM3_NVIC_ST_CAL     (*((volatile INT32U *)0xE000E01C))   /* SysTick Cal     Value Reg. */
// #define  OS_CPU_CM3_NVIC_PRIO_ST    (*((volatile INT8U  *)0xE000ED23))   /* SysTick Handler Prio  Reg. */

// #define  OS_CPU_CM3_NVIC_ST_CTRL_COUNT                    0x00010000     /* Count flag.                */
// #define  OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC                  0x00000004     /* Clock Source.              */
// #define  OS_CPU_CM3_NVIC_ST_CTRL_INTEN                    0x00000002     /* Interrupt enable.          */
// #define  OS_CPU_CM3_NVIC_ST_CTRL_ENABLE                   0x00000001     /* Counter mode.              */
// #define  OS_CPU_CM3_NVIC_PRIO_MIN                               0xFF     /* Min handler prio.          */

对应的还有这个函数也需要注释掉

//void  OS_CPU_SysTickInit (void)
//{
//    INT32U  cnts;
//
//
//    cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC;
//
//    OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);
//                                                 /* Set prio of SysTick handler to min prio.           */
//    OS_CPU_CM3_NVIC_PRIO_ST   = OS_CPU_CM3_NVIC_PRIO_MIN;
//                                                 /* Enable timer.                                      */
//    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
//                                                 /* Enable timer interrupt.                            */
//    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
/

那么这样,这个文件也解决掉了。继续下一个

五、在OS_dbg.c这个文件中

修改一个地方,#define  OS_COMPILER_OPT  __root,将后面的__root注释掉,否则会报错。自己可以试试

六、来到OS_cpu_a.asm这个汇编文件

1、里面的PUBLIC全改为EXPORT。这是有ARM汇编语言语言规定的。

2、RSEG CODE:CODE:NOROOT(2)    开辟代码段的格式也是需要修改的

修改如下:

		AREA |.text|, CODE , READONLY, ALIGN = 2
		THUMB
		REQUIRE8
		PRESERVE8
具体解释,看ARM的汇编编程介绍就知道了。

到这里,这个文件也修改完毕。

七、关于启动文件

有一个地方需要修改,那就是中断这部分。把启动代码中所有出现PendSV_Handler的地方替换成OS_CPU_PendSVHandler即可。

那么这个文件也修改完毕

到这里,我们的移植也就完成了一大部分,接下来就是编写自己的代码了。

八、编写几个简单的函数就能实现点灯了

#include "includes.h"

static OS_STK startup_task_stk[STARTUP_TASK_STK_SIZE];		  //定义栈
  
int main(void)
{
  	BSP_Init();
	OSInit();
	OSTaskCreate(Task_LED,(void *)0,
	&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);

	OSStart();
    return 0;
 }
 
 /*
 * 函数名:BSP_Init
 * 描述  :时钟初始化、硬件初始化
 * 输入  :无
 * 输出  :无
 */
void BSP_Init(void)
{
    LED_GPIO_Config();  /* LED 端口初始化 */
}

void Task_LED(void *p_arg)
{
   (void)p_arg;                		// 'p_arg' 并没有用到,防止编译器提示警告
	SysTick_init();
    while (1)
    {
        LED1( ON );
        OSTimeDlyHMSM(0, 0,0,500);
        LED1( OFF);
        OSTimeDlyHMSM(0, 0,0,500);
    }
}
 
/*
 * 函数名:SysTick_init
 * 描述  :配置SysTick定时器
 * 输入  :无
 * 输出  :无
 */
void SysTick_init(void)
{
    SysTick_Config(SystemCoreClock /OS_TICKS_PER_SEC);//初始化并使能SysTick定时器
}
到这里就实现单任务系统了,OK。点灯完毕!接下来就是仔细分析源码了。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于STM32F103ZET6的通过Modbus-485RTU协议采集pH和溶解氧数据需要进行以下步骤: 1. 首先,我们需要准备一块STM32F103ZET6开发板作为主控制器,该微控制器具有强大的计算和通信能力。另外,还需要一个RS485通信模块,该模块将实现STM32与外部设备的通信。 2. 接下来,我们需要连接pH和溶解氧传感器到STM32开发板。这些传感器通常具有模拟输出,我们需要将其连接到STM32的模拟输入引脚上。 3. 然后,在STM32开发板上编写代码。首先,我们需要初始化串口通信,设置通信参数,包括波特率和数据位数等。接着,我们需要编写Modbus协议的相关代码,实现数据的读取和写入功能。这可以使用现有的Modbus库来简化开发流程。 4. 在代码中,我们需要设置STM32的定时器,以固定的时间间隔读取pH和溶解氧传感器的数据。然后,通过Modbus协议将这些数据封装为Modbus数据包,并通过RS485通信模块发送给外部设备。 5. 外部设备接收到Modbus数据包后,会解析其中的数据,并进行相应的处理。例如,可以在外部设备上显示pH和溶解氧数值,或者将这些数据存储在数据库中进行后续的分析。 通过以上步骤,我们可以实现基于STM32F103ZET6的Modbus-485RTU协议采集pH和溶解氧数据的功能。这种方案具有高效、稳定和可靠的特点,适用于需要远程监测和控制环境参数的应用场景,例如水质监测和水产养殖等领域。 ### 回答2: 基于STM32F103ZET6芯片,我们可以通过Modbus-485RTU协议实现PH和溶解氧数据的采集。Modbus-485RTU协议是一种串行通信协议,常用于工业自动化领域,通过采用RS485总线传输数据,具有传输距离远、抗干扰能力强等特点。 首先,我们需要使用STM32F103ZET6芯片搭建硬件平台。该芯片具有丰富的外设接口,如USART、GPIO等。我们可以通过连接STM32F103ZET6芯片的USART接口和RS485模块,实现与外部设备的通信。 接下来,我们需要编写软件程序实现Modbus协议的功能。在STM32F103ZET6芯片上,可以使用相关的开发工具,如Keil MDK等进行开发。通过编写C语言程序并使用相应的库函数,我们可以实现Modbus-485RTU协议的编码和解码,以及数据的读取和写入。 对于PH和溶解氧数据的采集,我们可以使用相关的传感器。连接传感器到STM32F103ZET6芯片的IO口,并通过程序读取传感器输出的模拟信号。对于PH值的采集,我们可以使用PH传感器,通过将传感器输出的电压信号转换为数字信号,便可以得到PH值。对于溶解氧值的采集,我们可以使用溶解氧传感器,通过读取传感器输出的模拟电流信号并进行一定的计算,即可得到溶解氧值。 最后,在程序中实现Modbus协议的逻辑,通过Modbus指令对PH和溶解氧数据进行读写操作。通过编码和解码过程,可以将数据正确地传输给外部设备,实现与其他设备的通信。 总的来说,基于STM32F103ZET6芯片,使用Modbus-485RTU协议采集PH和溶解氧数据需要搭建硬件平台、编写软件程序,并连接传感器进行数据的获取。通过这些步骤,我们可以实现PH和溶解氧数据的采集与传输。 ### 回答3: 基于STM32F103ZET6微控制器,可以通过Modbus-485RTU协议来采集pH和溶解氧数据。 首先,我们需要连接STM32F103ZET6与pH和溶解氧传感器之间的Modbus-485RTU通信线路。该线路由一个RS-485转接器负责,将STM32F103ZET6的UART串口信号转换为RS-485电平信号,并通过一根485通信线连接到pH和溶解氧传感器。 接下来,我们需要在STM32F103ZET6上编写相应的软件程序来实现Modbus-485RTU通信协议。可以使用现有的Modbus库来简化开发过程。首先,需要配置STM32的UART串口通信参数,例如波特率、数据位、停止位和校验位等。然后,按照Modbus协议的规定,编写发送和接收数据的函数。 在发送方面,我们可以根据Modbus协议要求,构建相应的读取和写入命令,并通过UART串口发送给pH和溶解氧传感器。在接收方面,我们需要设置一个接收缓冲区来接收传感器返回的响应数据,并进行解析和处理。可以根据Modbus协议的规定,解析响应数据,获取pH和溶解氧数据,并进行进一步的处理和显示。 最后,我们可以根据具体的应用需求,将采集到的pH和溶解氧数据进行进一步的存储、显示或发送到其他设备,如计算机或上位机等。 总之,基于STM32F103ZET6微控制器,通过Modbus-485RTU协议采集pH和溶解氧数据需要我们进行硬件连接以及编写相应的软件程序来实现通信协议的要求,并对接收到的数据进行合理处理和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值