uCOS-III 学习记录(3)——空闲任务和阻塞延时
参考内容:《[野火]uCOS-III内核实现与应用开发实战指南——基于STM32》第 8 章。 1. 空闲任务 不知道有没有注意到这样一个问题:我在学习 x86 汇编语言的时候,曾详细研读过系统内核的代码,内核本身也是有自己的 TCB 的,内核可作为一个“任务管理器”来对其他任务进行创建、删除等操作。那么 uCOS 作为一个实时操作系统,内核也应该需要自己的任务和 TCB,因此我们需要创建一个空闲任务给内核,这样,在没有任务的时候,内核空转运行空闲任务,同时检查各个任务的状态以做出相应的操作(因此 uCOS 内核也可视为“任务管理器”)。 1.1 数据类型定义 空闲任务虽然与其他任务的作用不同,但它的本质依然是一个任务,TCB、任务栈一个都不能少。 1.1.1 空闲任务 TCB (os.h) 在 os.h 中定义 TCB: 1OS_EXT OS_TCB OSIdleTaskTCB; 1.1.2 空闲任务栈 (os_cfg_app.c) 有关空闲任务栈的定义,并不在 os.h 中。 首先在 os_cfg_app.h 中定义了空闲任务栈的大小(感觉叫栈尺寸更合适?栈粒度应该是 ...
uCOS-III 学习记录(1)——任务的创建、切换和OS的启动
参考内容:《[野火]uCOS-III内核实现与应用开发实战指南——基于STM32》第 6 章。 前排提醒 每一节标题最后的括号是表明该数据类型或函数位于哪个文件中。 按照 μC/OS-III 中的函数命名规则,以大小的 OS 开头,表示这是一个外部函数,可以由用户调用,以 OS_ 开头的函数表示内部函数,只能由 μC/OS-III 内部使用。紧接着是文件名,表示该函数放在哪个文件,最后是函数功能名称。例如:OSTaskCreate,说明允许用户调用,位于 os_task.c 文件中。 extern 的巧妙定义 (os.h): 12345#ifdef OS_GLOBALS #define OS_EXT#else #define OS_EXT extern#endif 在 cpu.h 和 os_type.h 中: 1234567891011121314151617181920212223242526272829#ifndef CPU_H#define CPU_Htypedef unsigned short CPU_INT16U;typedef unsigned int ...
STM8驱动温度传感器DS18B20
使用软件:IAR FOR STM8 编程方式:固件库 硬件配套:STM8S105K4T6最小系统板 这是我在做课设时摸索出来的代码,现记录如下: 1. DS18B20.h 1234567891011121314151617181920212223242526272829303132333435363738#ifndef __DS18B20_H#define __DS18B20_H/***********DS18B20驱动***********//*****要用RESET判断*****/#include "stm8s.h"#include "delay.h"/***********Definition***********/#define RESPONSE_MAX_TIME_1 200#define RESPONSE_MAX_TIME_2 240#define DS18B20_DQ_PORT (GPIOD)#define DS18B20_DQ_PIN (GPIO_PIN_4) /* PA4 */#define DS18B20_D...
STM8串口通信UART驱动
使用软件:IAR FOR STM8 编程方式:固件库 硬件配套:STM8S105K4T6最小系统板 注意事项:需在IAR工程配置中:在 General Options->Library Configuration->Library 选择 Full;在 General Options->Library Options->Printf formatter 选择 Large,Math functions 选择 Default;另外不能串口打印小数,需进一步处理数据 这是我在做课设时参考的代码,现记录如下: 1. uart.h 1234567891011121314151617181920212223#ifndef __UART_H#define __UART_H#include "stm8s.h"#include "stdio.h"#ifdef _RAISONANCE_#define PUTCHAR_PROTOTYPE int putchar (char c)#define GETCHAR_PROTOTYPE int ge...
STM8四线驱动LCD1602
使用软件:IAR FOR STM8 编程方式:固件库 硬件配套:STM8S105K4T6最小系统板 这是我在做课设时摸索出来的代码,现记录如下: 1. LCD1602.h 12345678910111213141516171819202122232425262728293031323334353637383940414243444546#ifndef __LCD1602_H#define __LCD1602_H/***********LCD1602 四线驱动***********/#include "stm8s.h"#include "delay.h"/***********Definition***********/#define LINE0 0x80#define LINE1 0xC0#define Rx_PORT (GPIOB)#define RS_PIN (GPIO_PIN_4) /* PB4 */#define RW_PIN (GPIO_PIN_3) /* PB3 */ /* NOT USE(RW接地) */#define...
C++并发与多线程(5)——call_once和条件变量condition_varible
一、call_once 在多线程的环境下,有些时候我们不需要某给函数被调用多次或者某些变量被初始化多次,它们仅仅只需要被调用一次或者初始化一次即可。 为了解决上述多线程中出现的资源竞争导致的数据不一致问题,我们大多数的处理方法就是使用互斥锁来处理。在C++11中提供了最新的处理方法:使用std::call_once函数模板来处理,需包含头文件#include<mutex>。 头文件内对此的定义如下: 12template <class Fn, class... Args>void call_once (once_flag& flag, Fn&& fn, Args&&... args); 第一个参数是一个标记,第二个参数可以是函数、成员函数、函数对象、lambda函数。 call_once()需要与一个标记结合使用,这个标记为std::once_flag。其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。 多个线程同时执行时,一个线程会等待...
C++并发与多线程(4)——unique_lock详解
一、unique_lock取代lock_guard unique_lock比lock_guard灵活很多(多出来很多用法),但是效率差一点,内存的占用也会大一点。 cppreference对此的描述是: A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked. On construction (or by move-assigning to it), the object acquires a mutex object, for whose locking and unlocking operations becomes responsible. The object supports both states: locked and unlocked. This class guarantees an unlocked status on destruction (even if not called expl...
C++并发与多线程(3)——互斥量与死锁
零、引子 1.创建多线程 在前几次学习中,我们都是创建一个子线程,其实多个子线程是比较常见的。一般在创建多个线程时,把thread对象放入到容器中管理,看起来像个thread对象的数组,对一次创建大量的线程并对大量线程进行管理有好处。下面是一个例子: 123456789101112131415161718192021222324252627#include <iostream>#include <thread>#include <vector>using namespace std;void get_id(int i){ cout << "第" << i << "线程id为" << this_thread::get_id() << "开始执行" << endl; cout << "第" << i << "线程id为" <&l...
C++并发与多线程(2)——线程传参问题
零、复习隐式转换和显式转换的概念 隐式转换(系统根据程序的需要而自动转换的): 123456789void fun(CTest test); class CTest { public: CTest(int m = 0); } fun(20);//隐式转换,这里的20生成了一个临时对象 显式转换(需要加括号标注想要转换的类型): 12345678910void fun(CTest test); //但有时隐式转换并不是我们想要的,可在构造函数前加上关键字explicit,来指定显式调用class CTest { public: explicit CTest(int m = 0); } fun(20);//错误,隐式转换fun(static_cast<CTest>(20)); //正确,显式转换,这里的20生成了一个临时对象 一、获得线程id 格式:std::thread::get_id cpp官网解释: Get thread id Returns the thread id. If the thread ...
C++并发与多线程(1)——创建线程
零、注意事项 程序运行起来,生成一个进程,该进程所属的主线程开始自动运行;当主线程从main()函数返回,则整个进程执行完毕。 主线程从main()开始执行,那么我们自己创建的线程,也需要从一个函数开始运行,一旦这个函数运行完毕,线程也结束运行。 整个进程是否执行完毕的标志是:主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了,此时如果其他子线程还没有执行完,也会被强行终止(此条有例外,以后会解释)。 一、创建线程的一般方法 首先要引入头文件#include,C++11中管理线程的函数和类在该头文件中声明,其中包括std::thread类。 创建线程的格式是std::thread mythread(function);,意思是创建了一个名为mythread的线程,并且线程mythread开始执行。其中可调用对象名(即括号中的function)作为第一个参数,第二个参数为该函数的第一个参数,如果该函数接收多个参数就依次写在后面。此时线程开始执行。 需要注意,线程类参数是一个可调用对象,C++中的可调用对象可以是函数、函数指针、lambda表达式、bind创建的对象...



