在Keil中使用RTOS v2, 以STM32为例

RTOSv2 Project Guide

Start a New RTOS v2 Project

首先,在这里说明一下,RTOS的官方手册,在环境管理中可以很直接通过点击文件来直达,不过在这里再列一下网址:http://www.keil.com/pack/doc/CMSIS/Driver/html/group__usart__interface__gr.html#details

同keil新建工程的工程一样,先准备选择一个文件夹来保存工程。

在这里插入图片描述

选择合适的MCU型号

在这里插入图片描述

然后,环境管理界面弹出,分别选择CMSIS – > CORE;CMSIS – > RTOS(API)–> Keil RTX5 ;CMSIS – > RTOS2(API)–> Keil RTX5(右边的Variant 选择Library);Device --> GPIO+Startup; Device --> StdPeriph Drivers --> EXTI+Framework+GPIO+RCC+USART+TIM+IWDG+WWDG(这是几个常用的,以后添加可以按需添加,以后也可以随时添加);CMSIS Drivers --> USART(API)–>USART;如下所示。接下来点击确定,新的工程就建好了。

在这里插入图片描述

点击左边的文件树列表,如下图。

在这里插入图片描述

接下来进入工程根目录下,建一个文件夹(这里为Custom)用来保存我们自己的代码。

在这里插入图片描述

接下来,将我们已经写好的代码直接搬过来。主要是main.c文件和开发板上按键和led的代码,boardled.c, boardled.h, boardkey.c, boardkey.h。这些文件分别是附录中的文件1,2,3,4,5。

在这里插入图片描述

然后,回到IDE工程中,开始将这些文件添加到工程中。

在这里插入图片描述

进入Custom文件夹,将下面的文件类型选择为所有文件类型,这样就可以将.h文件也添加到工程中,在这里添加头文件并不能让它们可以被工程使用,这里添加头文件的目的是,这样可以直接在IDE的工程文件栏中显示,直接打开编辑,方便用户使用。
在这里插入图片描述

如上所言,让工程使用头文件还需要在option中那个设置。

在这里插入图片描述

按照如下步骤一次,1. 选择C/C++菜单栏,2. 点击包含路径,3. 添加路径选项,4. 浏览目录 ,5. 选择有头文件的文件夹,6. 点击选择文件夹。

在这里插入图片描述

顺便,如下依次配置好option,这在前面的教程中已经做过了,不再详述。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码在后面的附录中,其功能是让板上的KEY 1控制 LED1,KEY 2控制 LED2,按键按下,明灭状态就变换一次。这是一个很简单的例子。

在这里插入图片描述

重建所有的目标文件后,下载到板上。

在这里插入图片描述

在这里插入图片描述

板子的接线和效果如下所示:

在这里插入图片描述

2. Config USART and Use USART API

RTOS中USART的配置已经很容易操作了,但是为了满足正常的需求,作者这里有添加了一些小函数,有些函数只有其中一个USART有,若读者需要可以自行修改添加。文件为serial.h和serial.c,见附录文件

首先,将用到的文件,serial.c serial.h 见附录代码7和附录代码8添加到工程中,main.c的修改为附录6中的代码, 代码中也同时包含了配置了新线程微信线程分配资源的示例。

在这里插入图片描述

再次进入环境管理界面,添加如下两个库文件,点击OK。

在这里插入图片描述

然后,比较重要的事情来了,在RTOS中要正常使用其驱动API还需要做一些额外设置,去打开这些外设,配置文件为RTE_Device.h 。

在这里插入图片描述

进入该文件后,是看一看到定义了很多内容,但我们想要是用什么并不清楚,但是,可以看到代码界面下方有两个选项,直接切入Configuration Wizard。

在这里插入图片描述

进去会发现,突然有种豁然开朗的感觉。可以看到时钟已经配置完毕。然后点击+,配置USART1和USART2。记得要保存。配置如下:

在这里插入图片描述

接下来,将程序重建,下载到开发板上。使用USB转串口工具,将USART1跟电脑连接起来。打开串口调试工具,找到正确的端口,将波特率设置为9600,发送AT+CGATT?加回车(实际发送: “AT+CGATT?\r\n”)。main.c 中的代码,在m5310模组和电脑之间建立虚拟链接。所以会收到如下所示内容。

在这里插入图片描述

附录

  1. Filename: main.c
/*----------------------------------------------------------------------------
    
    Designers Guide to the Cortex-M Family
    CMSIS RTOS Threads Example

*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
  Include the microcontroller header for register defenitions and CMSIS core functions
    Include the CMSIS RTOS header for the RTOS API
 *---------------------------------------------------------------------------*/

//#include "STM32F10x.h"
#include <cmsis_os2.h>
#include <cmsis_os.h>
#include "boardled.h"//板上LED
#include "boardkey.h"//板上按键

//按键事件,在boardkey中声明且调用,当有按键事件,调用(执行)此函数
//这里执行的内容是按下按键,对应LED的亮灭状态变换一下。LED1对应KEY1,LED2对应KEY2。
void KEY_Event(uint8_t num){
    static uint8_t falg01 = 1;
    static uint8_t falg02 = 1;
    if(num == 4){
        if(falg01){
            LED_On(0);
            falg01 = 0;
        }
        else{
            LED_Off(0);
            falg01 = 1;
        }
    }
    else if(num == 5)
        {
        if(falg02){
            LED_On(1);
            falg02 = 0;
        }
        else{
            LED_Off(1);
            falg02 = 1;
        }
    }
}
//线程1,执行LED和按键的初始化后挂起
void thread1 (void *argument) 
{
    LED_Initialize ();
    KEY_Initialize ();
    osSignalWait(0x01, osWaitForever);

}
//系统初始化,开始一个新线程
int main (void) 
{
    SystemCoreClockUpdate();
    osKernelInitialize ();                    // initialize CMSIS-RTOS
    osThreadNew(thread1,NULL,NULL);
    osKernelStart();                         // start thread execution 
    while(1);
}
  1. Filename: boardled.h
#ifndef __BOARDLED_H
#define __BOARDLED_H
#include "GPIO_STM32F10x.h"

int32_t LED_Initialize (void);
int32_t LED_Uninitialize (void);
int32_t LED_On (uint32_t num);
int32_t LED_Off (uint32_t num);
int32_t LED_SetOut (uint32_t val);
uint32_t LED_GetCount (void);

void thread_keyrun (void *argument);
int32_t KEY_Initialize (void);

#endif   /*__BOARDLED_H*/
  1. Filename: boardled.c
#include "boardled.h"
#include <cmsis_os.h>

/*There is 2 LED , LDE1 is ctrolled by PB0, LDE2 ctrolled by PB1*/
const GPIO_PIN_ID Pin_LED[] = { //引脚描述结构体
    {GPIOB,  0},
    {GPIOB,  1},
};
#define LED_COUNT (sizeof(Pin_LED)/sizeof(GPIO_PIN_ID))

int32_t LED_Initialize (void) { //使用RTOS API配置GPIO
  uint32_t n;
  /* Configure pins: Push-pull Output Mode (50 MHz) with Pull-down resistors */
  for (n = 0; n < LED_COUNT; n++) {
    GPIO_PortClock   (Pin_LED[n].port, true);
    GPIO_PinWrite    (Pin_LED[n].port, Pin_LED[n].num, 0);
    GPIO_PinConfigure(Pin_LED[n].port, Pin_LED[n].num,
                      GPIO_OUT_PUSH_PULL,
                      GPIO_MODE_OUT2MHZ);
  }
  return 0;
}

int32_t LED_Uninitialize (void) {
  uint32_t n;

  /* Configure pins: Input mode, without Pull-up/down resistors */
  for (n = 0; n < LED_COUNT; n++) {
    GPIO_PinConfigure(Pin_LED[n].port, Pin_LED[n].num,
                      GPIO_IN_FLOATING,
                      GPIO_MODE_INPUT);
  }
  return 0;
}

int32_t LED_On (uint32_t num) {   //开LED灯,如果超出操作范围,返回错误值-1
  int32_t retCode = 0;

  if (num < LED_COUNT) {
    GPIO_PinWrite(Pin_LED[num].port, Pin_LED[num].num, 1);
  }
  else {
    retCode = -1;
  }
  return retCode;
}

int32_t LED_Off (uint32_t num) {
  int32_t retCode = 0;

  if (num < LED_COUNT) {
    GPIO_PinWrite(Pin_LED[num].port, Pin_LED[num].num, 0);
  }
  else {
    retCode = -1;
  }

  return retCode;
}

int32_t LED_SetOut (uint32_t val) {
  uint32_t n;

  for (n = 0; n < LED_COUNT; n++) {
    if (val & (1<<n)) {
      LED_On (n);
    } else {
      LED_Off(n);
    }
  }

  return 0;
}

uint32_t LED_GetCount (void) {

  return LED_COUNT;
}
  1. Filename: boardkey.h
/*由于RTOS中没有外部中断的API,因此这里直接使用标准库的函数来配置*/
#ifndef __BOARDKEY_H
#define __BOARDKEY_H
#include "GPIO_STM32F10x.h"
#include "stm32f10x_exti.h"
#include <cmsis_os.h>

int32_t KEY_Initialize (void);

#endif   /*__BOARDKEY_H*/
  1. Filename: boardkey.c
 /*由于RTOS中没有外部中断的API,因此这里直接使用标准库的函数来配置*/
#include "boardkey.h"

extern void KEY_Event(uint8_t num);

int32_t KEY_Initialize (void) {
        GPIO_InitTypeDef GPIO_InitStructure; 
        EXTI_InitTypeDef EXTI_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;    
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);//打开GPIO AFIO的时钟
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
      GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource4); //选择EXTI信号源 
        EXTI_ClearITPendingBit(EXTI_Line4);                                                                       
    EXTI_InitStructure.EXTI_Line = EXTI_Line4;               //中断线选择
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;      //EXTI为中断模式
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                //使能中断
    EXTI_Init(&EXTI_InitStructure); 
 
      GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5); //选择EXTI信号源
        EXTI_ClearITPendingBit(EXTI_Line5);
      EXTI_InitStructure.EXTI_Line = EXTI_Line5;               //中断线选择

    EXTI_Init(&EXTI_InitStructure); 
        
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);           //配置NVIC优先级分组为1
    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;        //中断源stm32f10x.h”中
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级:1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        //子优先级:1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_Init(&NVIC_InitStructure);
        
        NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; 
        NVIC_Init(&NVIC_InitStructure);
  return 0;
}
//中断服务函数的名称要特别小心,因为你随便写错一点,编译不会产生报错,但是会导致程序无法进入中断服务程序,甚至卡死。不确定的话可以到启动文件startup_stm32f10x_md.s中查找。
void EXTI4_IRQHandler(void)  //按键1,PC4中断服务函数                     
{
  if(EXTI_GetITStatus(EXTI_Line4)!= RESET)  
  {  
    EXTI_ClearITPendingBit(EXTI_Line4);
      KEY_Event(4);
  }   
}

void EXTI9_5_IRQHandler(void)                       
{
  if(EXTI_GetITStatus(EXTI_Line5)!= RESET)  
  {  
    EXTI_ClearITPendingBit(EXTI_Line5);
      KEY_Event(5);
  }   
}
  1. Filename: main.c
 /*----------------------------------------------------------------------------
    
    Designers Guide to the Cortex-M Family
    CMSIS RTOS Threads Example

*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
  Include the microcontroller header for register defenitions and CMSIS core functions
    Include the CMSIS RTOS header for the RTOS API
 *---------------------------------------------------------------------------*/

//#include "STM32F10x.h"
#include <cmsis_os2.h>
#include <cmsis_os.h>
#include "boardled.h"
#include "boardkey.h"
#include "serial.h"

static uint64_t thread1_stk[128];
static uint64_t thread1_cdm[128];
void KEY_Event(uint8_t num){
static uint8_t falg01 = 1;
    static uint8_t falg02 = 1;
    if(num == 4){
        if(falg01){
            LED_On(0);
            falg01 = 0;
        }
        else{
            LED_Off(0);
            falg01 = 1;
        }
    }
    else if(num == 5)
        {
        if(falg02){
            LED_On(1);
            falg02 = 0;
        }
        else{
            LED_Off(1);
            falg02 = 1;
        }
    }
}

void thread1 (void *argument) 
{
    KEY_Initialize ();
    LED_Initialize ();
    osSignalWait(0x01, osWaitForever);
}

void thread2 (void *argument) 
{
    //osSignalWait(0x01, osWaitForever);
  char temp1;
    char temp2;

    Serial1_Conf(9600);
    Serial2_Conf(9600);

    Serial1_Print("Usart1 Initialize Finished!\r\n");
    osDelay(100);

    while(1){
        if(USART1_RecNum()){
        USART2_SendByte(USART1_ReadByte());     
        }
        if(USART2_RecNum()){
      USART1_SendByte(USART2_ReadByte());   
        }
    }
}

static osThreadAttr_t thread2_attr;

int main (void) 
{
    thread2_attr.stack_mem  = thread1_stk;
  thread2_attr.stack_size = sizeof(thread1_stk);
    //thread1_attr.priority = osPriorityHigh;
    thread2_attr.cb_mem = thread1_cdm;
    thread2_attr.cb_size = sizeof(thread1_cdm);
    SystemCoreClockUpdate();
    osKernelInitialize ();                    // initialize CMSIS-RTOS
    osThreadNew(thread1,NULL,NULL);
    osThreadNew(thread2,NULL,&thread2_attr);
    osKernelStart();                         // start thread execution 
    while(1);
}
  1. Filename: serial.h
#ifndef __SERIAL_H
#define __SERIAL_H
#include "GPIO_STM32F10x.h"
#include "Driver_USART.h"
#include <cmsis_os.h>

extern ARM_DRIVER_USART Driver_USART1;//导入RTOS API的USART1 
extern ARM_DRIVER_USART Driver_USART2;
#define Serial1 Driver_USART1 //转换为更加熟悉的Serial1
#define Serial2 Driver_USART2

char USART1_ReadByte(void);
char USART1_SendByte(char data);
char USART2_ReadByte(void);
char USART2_SendByte(char data);
uint8_t USART2_Read(char buffer[],uint8_t num);
uint8_t USART2_ReadLine(char buffer[]);
uint8_t USART1_RecNum(void);
uint8_t USART2_RecNum(void);
void USART1_callback(uint32_t event);
void USART2_callback(uint32_t event);
void Serial2_Conf(uint32_t baud);
void Serial1_Conf(uint32_t baud);
int Serial1_Print(char str[]);
int Serial2_Print(char str[]);
#endif   /*__SERIAL_H*/
  1. Filename: serial.c
 #include "serial.h" 
    char RxBuf1[256]={0}; //自定义的接收缓存
    static uint8_t Num_U1RxByte = 0;    //USART1 接收的数据字节数
    static uint8_t U1RxF = 0; //索引,指向USART1 接收的数据字缓存中未读数据的第一个
    static uint8_t U1RxL = 0;//索引,指向USART1 接收的数据字缓存中未读数据的最后一个
    char Rx1; //一个临时接收变量
    //这里将缓存用作FIFO,将索引定义为8位无符号数,范围正是缓存的大小,
    //溢出后正好回到缓存的开始,遍历所有缓存
    
    
    char RxBuf2[256]={0};
    static uint8_t Num_U2RxByte = 0;    
    static uint8_t U2RxF = 0;
    static uint8_t U2RxL = 0;
    char Rx2;

/*
    *@brief: 从USART1缓存中读走一个字节
 */ 
char USART1_ReadByte(void){
    if(Num_U1RxByte == 0) return '\0';  
    Num_U1RxByte--;
    return RxBuf1[U1RxF++];
}
/*
    *@brief: USART1发送一个字节,直至发送完,超过10s算超时,返回1
 */ 
char USART1_SendByte(char data){
    uint16_t i = 0;
    Serial1.Send(&data,1);
    for(;i<1000;i++){
        if(Serial1.GetTxCount()>=1)return 0;
        osDelay(10);
    }
    return 1;
}
char USART2_ReadByte(void){
    if(Num_U2RxByte == 0) return '\0';  
    Num_U2RxByte--;
    return RxBuf2[U2RxF++];
}
char USART2_SendByte(char data){
    uint16_t i = 0;
    Serial2.Send(&data,1);
    for(;i<1000;i++){
        if(Serial2.GetTxCount()>=1)return 0;
        osDelay(10);
    }
    return 1;
}
/*
    *@brief: 获取USART1缓存RxBuf1中缓存的字节数
 */
uint8_t USART1_RecNum(void){
        return Num_U1RxByte;
}
uint8_t USART2_RecNum(void){
        return Num_U2RxByte;
}

/*
    *@brief: 配置USART1,且使波特率为baud
 */
void Serial1_Conf(uint32_t baud){
        /*Initialize the USART driver */
    Serial1.Initialize(USART1_callback);
    /*Power up the USART peripheral */
    Serial1.PowerControl(ARM_POWER_FULL);
    /*Configure the USART to baud Bits/sec */
    Serial1.Control(ARM_USART_MODE_ASYNCHRONOUS |
                      ARM_USART_DATA_BITS_8 |
                      ARM_USART_PARITY_NONE |
                      ARM_USART_STOP_BITS_1 |
                      ARM_USART_FLOW_CONTROL_NONE, baud);
     
    /* Enable Receiver and Transmitter lines */
    Serial1.Control (ARM_USART_CONTROL_TX, 1);
    Serial1.Control (ARM_USART_CONTROL_RX, 1);
        Serial1.Receive(&Rx1,1);
}
void Serial2_Conf(uint32_t baud){
        /*Initialize the USART driver */
    Serial2.Initialize(USART2_callback);
    /*Power up the USART peripheral */
    Serial2.PowerControl(ARM_POWER_FULL);
    /*Configure the USART to baud Bits/sec */
    Serial2.Control(ARM_USART_MODE_ASYNCHRONOUS |
                      ARM_USART_DATA_BITS_8 |
                      ARM_USART_PARITY_NONE |
                      ARM_USART_STOP_BITS_1 |
                      ARM_USART_FLOW_CONTROL_NONE, baud);
     
    /* Enable Receiver and Transmitter lines */
    Serial2.Control (ARM_USART_CONTROL_TX, 1);
    Serial2.Control (ARM_USART_CONTROL_RX, 1);
        Serial2.Receive(&Rx2,1);
}
/*
    *@brief: USART1发送输出一个字符串,直至发送完毕
 */
int Serial1_Print(char str[]){
    int length = 0;
    uint16_t i = 0;
    while(str[length++]);
    length--;
    Serial1.Send(str,length);
    for(;i<1000;i++){
        if(Serial1.GetTxCount()>=length)return length;
        osDelay(30);
    }
    return -1;
}
int Serial2_Print(char str[]){
    int length = 0;
    uint16_t i = 0;
    while(str[length++]);
    length--;
    Serial2.Send(str,length);
    for(;i<1000;i++){
        if(Serial2.GetTxCount()>=length)return length;
        osDelay(30);
    }
    return -1;
}
/*
    *@brief: USART2读取num个数据,保存的buffer中
 */
uint8_t USART2_Read(char buffer[],uint8_t num){
    uint8_t count = 0;
    for(;count<num;count++){
        buffer[count] = USART2_ReadByte();
    }
    buffer[count] = '\0';
    return count;
}
/*
*@brief: 从缓存中等待读取一整行数据
*@note: for line ,condition is "\r\n" 
*/
uint8_t USART2_ReadLine(char buffer[]){
    uint8_t p=0;
    while(1){
        if(USART2_RecNum()){
            buffer[p] = USART2_ReadByte();
            if(buffer[p] == '\n'){
                buffer[--p] = 0;
                break;
            }
            else{
                p++;
            }
        }
    }
    return p;
}
/*
    *@brief: RTOS API中USART1的事件回调函数
    *@function:在这里仅将将数据转移到缓存中
*/
void USART1_callback(uint32_t event){
    /*
  uint32_t mask;
  mask = ARM_USART_EVENT_RECEIVE_COMPLETE  |
         ARM_USART_EVENT_TRANSFER_COMPLETE |
         ARM_USART_EVENT_SEND_COMPLETE     |
         ARM_USART_EVENT_TX_COMPLETE       ;
  if (event & mask) {
  }
    if (event & mask) {
  // Success: Wakeup Thread 
  //osSignalSet(tid2, 0x01);
  }
  if (event & ARM_USART_EVENT_RX_TIMEOUT) {
//    __breakpoint(0); //  Error: Call debugger or replace with custom error handling 
    }
  if (event & (ARM_USART_EVENT_RX_OVERFLOW | ARM_USART_EVENT_TX_UNDERFLOW)) {
//    __breakpoint(0);  // Error: Call debugger or replace with custom error handling 
  }
    */

    if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) {
        RxBuf1[U1RxL++] = Rx1;
        Serial1.Receive(&Rx1,1);
        if(Num_U1RxByte < 255)Num_U1RxByte++;
        else{
            U1RxF++; //当buffer满了丢弃最先收到的1个数据
        }
  }
    /*
    if (event & ARM_USART_EVENT_TRANSFER_COMPLETE) {
        U1Tx_Flag = true;
  }*/
}

void USART2_callback(uint32_t event){

    if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) {
        RxBuf2[U2RxL++] = Rx2;
        Serial2.Receive(&Rx2,1);
        if(Num_U2RxByte < 255)Num_U2RxByte++;
        else{
            U2RxF++; 
        }
  }
    /*
    if (event & ARM_USART_EVENT_TRANSFER_COMPLETE) {
        U2Tx_Flag = true;
  }*/
        
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值