全网最简单的stm32f103c8t6移植ucosiii教程(附移植好的工程)

这篇具有很好参考价值的文章主要介绍了全网最简单的stm32f103c8t6移植ucosiii教程(附移植好的工程)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

   最近在做一个机器人项目,需要使用到stm32f103c8t6核心板。考虑程序中的多任务特性,因此决定使用ucosiii用于多任务管理。ucosiii移植可能对于一些嵌入式老鸟来说,可能是信手拈来,但是对于很多新手特别是刚入门的小白来说还是有一定的难度的。尤其是全网的移植教程过于杂乱良莠不齐,甚至有些博主将移植好的工程设置为付费下载。这里决定分享下我的移植过程,并在最后附上工程模板以供学习和参考。
   如果你同样是嵌入式方向的学习者,记得点击下关注哦,后期会分享更多的干货教程与实战项目以供大家学习。


一、ucosiii是什么?

   uCosIII,全称为Micro-Controller Operating Systems III,是一种轻量级实时操作系统(RTOS),被广泛应用于嵌入式系统中。它由美国Micrium公司开发,提供了一整套完整的多任务处理(Multi-Tasking)功能和软件源码,使得嵌入式系统开发能够更加快捷和高效。uCosIII具有高度的可定制性和可伸缩性,允许使用者按需组装需要的软件库,提供了良好的可移植性,可以在多种处理器和微控制器上运行。
   我们这里是基于正点原子官方ZET6的例程进行移植的,后续实现串口打印与点灯进行验证工程的正确性。

二、移植步骤

1.准备工作

   这里需要事先准备正点原子的工程:
   LED文件夹是移植成功的工程文件,UCOSIII源码是官方下载的源码,倘若想移植到别的系列可以直接移植UCOSIII源码,例6-1是原子哥的原工程。
stm32移植ucos,一起来学习STM32吧,stm32
链接:https://pan.baidu.com/s/18i3NMoFQqX9tNGFYCVjQ4w?pwd=1207
提取码:1207

2.修改芯片信息

   打开下载好的正点原子例程,点击魔术棒,选择芯片类型将其更改成STM32F103C8,然后确定。
stm32移植ucos,一起来学习STM32吧,stm32

3.解决delay不准的问题

   此时由于STM32F03ZET6和STM32F103C8T6的外部时钟频率不一样,因此delay.c里的delay_ms函数定义会出现不准的情况,这里的解决办法是在主函数的delay函数初始化之前添加 SystemInit();函数。
   这里解释下原理以及SystemInit()函数的功能:
   在STM32系列的微控制器中,SystemInit()函数是在启动时钟和系统时钟之前由硬件启动代码调用的函数之一。它是用于初始化芯片系统时钟和系统时钟源的函数,并通过配置STM32内部时钟发生器(Clock Generator)来为微控制器系统提供正确的系统时钟。SystemInit() 函数还会配置其他必要的系统时钟参数,如AHB总线时钟、APB总线时钟、外设时钟和定时器时钟等。
   在具体实现上,SystemInit()函数会通过读取存储在FLASH内的一组初始值来配置STM32的时钟,这些初始值通常是由厂商提供的初始化文件、库或工具生成的。SystemInit()函数还可以在初始化前或初始化后通过内部或者外部调用进行修改或补充。因此,如果你使用了其他的时钟源或者外设,你可以在SystemInit()函数中添加需要的配置来使STM32适应新的硬件设置。
   总之,SystemInit()函数是STM32系列微控制器启动时钟和系统时钟的实际配置入口,它确保了芯片系统时钟被设置为正确的频率,使得STM32在后续的软件开发和外部设备连接中能够正常运行。
stm32移植ucos,一起来学习STM32吧,stm32

4. 删除lcd文件以及修改led.h中GPIO

   由于这里我们没有用到lcd,因此我们将他删除,并在main.c中删除lcd相关内容。我们使用到的stm32f103c8t6核心板的led是PC13,因此我们修改led.h与led.c文件。

led.h
#ifndef __LED_H
#define __LED_H	 
#include "sys.h"

#define LED0 PCout(13)// PC13
	

void LED_Init(void);//初始化

		 				    
#endif
led.c
#include "led.h"
void LED_Init(void)
{
 GPIO_InitTypeDef  GPIO_InitStructure;	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	 //使能PB,PE端口时钟
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOC, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOC,GPIO_Pin_13);						 //PB.5 输出高
}

   最后修改main函数,让三个任务:start_task创建task1和task2,创建完就删除自己。task1任务是led一秒闪烁与翻转一次,task2是空任务,task1task2都会通过串口一printf输出提示信息。

main.c如下:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "includes.h"

//任务优先级
#define START_TASK_PRIO		3
//任务堆栈大小	
#define START_STK_SIZE 		128
//任务控制块
OS_TCB StartTaskTCB;
//任务堆栈	
CPU_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *p_arg);

///任务二亮灯,并打印出信息
//任务优先级
#define TASK1_TASK_PRIO		4
//任务堆栈大小	
#define TASK1_STK_SIZE 		128
//任务控制块
OS_TCB Task1_TaskTCB;
//任务堆栈	
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);


///任务三,打印任务三执行信息
//任务优先级
#define TASK2_TASK_PRIO		5
//任务堆栈大小	
#define TASK2_STK_SIZE 		128
//任务控制块
OS_TCB Task2_TaskTCB;
//任务堆栈	
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
//任务函数
void task2_task(void *p_arg);



//主函数
int main(void)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	SystemInit();//由于本工程是由stm32f103zet6移植所来,因此这里因加入本函数确保delay函数正常使用
	delay_init();  //时钟初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
	uart_init(115200);   //串口初始化
	LED_Init();         //LED初始化	


	
	OSInit(&err);		    //初始化UCOSIII
	OS_CRITICAL_ENTER();	//进入临界区			 
	//创建开始任务
	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
				 (CPU_CHAR	* )"start task", 		//任务名字
                 (OS_TASK_PTR )start_task, 			//任务函数
                 (void		* )0,					//传递给任务函数的参数
                 (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                 (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                 (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                 (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,					//用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err);				//存放该函数错误时的返回值
	OS_CRITICAL_EXIT();	//退出临界区	 
	OSStart(&err);      //开启UCOSIII
}


//开始任务任务函数
void start_task(void *p_arg)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;

	CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);  	//统计任务                
#endif
	
#ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();	
#endif
	
#if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif	
	
	OS_CRITICAL_ENTER();	//进入临界区
	//创建TASK1任务
	OSTaskCreate((OS_TCB 	* )&Task1_TaskTCB,		
				 (CPU_CHAR	* )"Task1 task", 		
                 (OS_TASK_PTR )task1_task, 			
                 (void		* )0,					
                 (OS_PRIO	  )TASK1_TASK_PRIO,     
                 (CPU_STK   * )&TASK1_TASK_STK[0],	
                 (CPU_STK_SIZE)TASK1_STK_SIZE/10,	
                 (CPU_STK_SIZE)TASK1_STK_SIZE,		
                 (OS_MSG_QTY  )0,					
                 (OS_TICK	  )0,					
                 (void   	* )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);				
				 
	//创建TASK2任务
	OSTaskCreate((OS_TCB 	* )&Task2_TaskTCB,		
				 (CPU_CHAR	* )"task2 task", 		
                 (OS_TASK_PTR )task2_task, 			
                 (void		* )0,					
                 (OS_PRIO	  )TASK2_TASK_PRIO,     	
                 (CPU_STK   * )&TASK2_TASK_STK[0],	
                 (CPU_STK_SIZE)TASK2_STK_SIZE/10,	
                 (CPU_STK_SIZE)TASK2_STK_SIZE,		
                 (OS_MSG_QTY  )0,					
                 (OS_TICK	  )0,					
                 (void   	* )0,				
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, 
                 (OS_ERR 	* )&err);			 
	OS_CRITICAL_EXIT();	//退出临界区
	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
}


//task1任务函数
void task1_task(void *p_arg)
{
	u8 task1_num=0;
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;
	
	OS_CRITICAL_ENTER();
	
	OS_CRITICAL_EXIT();
	while(1)
	{
		task1_num++;	//任务执1行次数加1 注意task1_num1加到255的时候会清零!!
		LED0= ~LED0;
		printf("任务1已经执行:%d次\r\n",task1_num);
//		if(task1_num==5) 
//		{
//			OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err);	//任务1执行5此后删除掉任务2
//			printf("任务1删除了任务2!\r\n");
//		}

		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时1s
		
	}
}

//task2任务函数
void task2_task(void *p_arg)
{
	u8 task2_num=0;
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;
	
	OS_CRITICAL_ENTER();//进入临界区		

	OS_CRITICAL_EXIT();//退出临界区域
	while(1)
	{
		task2_num++;	//任务2执行次数加1 注意task1_num2加到255的时候会清零!!

		printf("任务2已经执行:%d次\r\n",task2_num);

		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时1s
	}
}

三. 现象验证

   使用usb转ttl用串口下载程序至单片机内,打开串口助手、并观察板载LED闪烁情况:
stm32移植ucos,一起来学习STM32吧,stm32
两秒的视频可以看到灯闪烁两次

STM32F103C8T6移植UCOSIII验证视频

制作不易,点个关注吧。文章来源地址https://www.toymoban.com/news/detail-563023.html

到了这里,关于全网最简单的stm32f103c8t6移植ucosiii教程(附移植好的工程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 舵机控制(STM32F103C8T6)

            本文是以 STM32F103C8T6 作为主控芯片,通过PB6端口输出PWM,实现控制180°舵机。 (一)概述         舵机是一种位置伺服驱动器器,是一种带有输出轴的小装置。当我们向伺服器发送一个控制信号时,输出轴就可以转到特定的位置。只在控制信号持续不变,伺服机构就

    2023年04月09日
    浏览(20)
  • STM32F103C8T6板子介绍

    STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器 STM32常应用在嵌入式领域,如智能车、无人机、机器人、无线通信、物联网、工业控制、娱乐电子产品等 STM32功能强大、性能优异、片上资源丰富、功耗低,是一款经典的嵌入式微控制器。  STM32F103C8T6 F1XX片上资源

    2024年02月11日
    浏览(22)
  • STM32F103C8T6系统板

    1.电源部分 2.复位 3.晶振 4. 电源电路——防反接 有关二极管 漫谈二极管防电源反接电路 本次采用上图右下角的NMOS防反接电路。 电源电路——电源芯片 AMS1117是AMS公司的 ,LM1117是NS(美国国家半导体)的,LM1117要贵很多,所以一般的用AMS1117就可以了。 (以下分析参考STM32F10

    2024年02月02日
    浏览(28)
  • STM32F103C8T6串口通信

      首先来看一下需要操作的函数,以及配置的步骤: 图1                                                  图2   Code: usart.c #include \\\"usart.h\\\" void ustart_Init(void ) { GPIO_InitTypeDef GPIO_Init_Ustar ; // 定义输出端口TX的结构体对象 USART_InitTypeDef USTART_Init; // 定义串口初始化结构体对象

    2024年02月16日
    浏览(22)
  • 功耗测评 | STM32F103C8T6

    STM32F103C8T6 MCU越来越广泛的应用在生产生活的各个领域,外接丰富的传感器、功能模块、通信模块、显示存储等可以形成各种可样的产品项目应用。对于功耗要求比较高的产品,一般会选择STM32L系列的MCU,但是从功耗的评测角度,逻辑上是基本相似的。 在很多应用场合中都对

    2024年02月07日
    浏览(17)
  • STM32F103C8T6 按键扫描输入

    第一章 STM32F103C8T6 点亮LED灯 系列文章目录 前言 一、原理  1.按键类型  2.按键消抖 3.IO口输入配置 1)模拟输出 2)浮空输入模式 3)下拉输入模式(PULL DOWN) 4)上拉输入模式(PULL UP) 二、代码部分 main.c key.c key.h 总结         上一章我们成功入门了STM32F103C8T6,今天我们来

    2023年04月23日
    浏览(32)
  • [STM32F103C8T6]ADC转换

    什么是ADC转换? ADC转换的全称是: Analog-to-Digital Converter ,指模拟 / 数字转换器 ADC的性能指标: ADC分辨率: SSA与VREF-一起接到地,DDA与VREF+接到3.3v,所以ADC转换的范围是0---3.3v 所以最后的ADC转换值应该是我们的测量值*分辨率    分辨率 = 3.3v/2^12 = (3.3/4096)   12位的转换器所

    2024年02月06日
    浏览(26)
  • STM32F103C8T6串口调试篇

    项目开发中,当出现bug时,由于不知道某个变量的值,所以很难定位问题,针对此问题,串口调试脱颖而出。通过串口printf()实时将需要显示的信息打印出来,这样就很方便的定位问题。 串口设置方法 1.购买调试器pwlink2。参考STM32F103C8T6程序烧录方法_stm32f103c8t6如何烧录_流

    2024年02月12日
    浏览(20)
  • stm32f103c8t6的外部中断

    在单片机中存在着中断系统,这个系统的逻辑和功能在51单片机中已经有所了解。 1.在32单片机中的内核有一个nvic 里面存放许多优先级的设定,外接许多中断源,比如“exti、tim、adc、usart等”接入之后,nvic再通过中断优先级进行排队,再内接入cpu中进行处理,这样子大大减少

    2024年02月09日
    浏览(19)
  • 嵌入式硬件——stm32F103C8T6

    如下图:    处理器核心:STM32F103C8T6内置了ARM Cortex-M3处理器,这是一种高性能、低功耗的32位RISC处理器,适用于嵌入式系统。 时钟速度:它可以工作在不同的时钟速度,最高主频可达72 MHz。 存储器:包括64KB的Flash程序存储器用于存储程序代码,以及20KB的SRAM用于存储数据和

    2024年02月05日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包