打印
[应用相关]

一种STM32的串口控制台的实现(非常实用)

[复制链接]
1952|30
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一.背景
曾经玩Linux时非常喜欢这种基于出串口的控制台, 通过简单的串口TX和RX能实现嵌入式硬件的人机交互,非常实用,  那么STM32能否实现通过超级终端与用户互动的构想呢? 答案是肯定的,由于这个UART控制平台就像应用程序套上一层可访问的外科(Shell)故而我将这种基于UART的控制平台简称Shell,构架和效果如下图:



使用特权

评论回复
沙发
八层楼|  楼主 | 2019-7-6 12:43 | 只看该作者

使用特权

评论回复
板凳
八层楼|  楼主 | 2019-7-6 12:43 | 只看该作者
这张图箭头指向的是输入的指令,其余是STM32串口输出的信息,, 可以看到通过这些简单的指令输入我们通过Shell可以做很多事情:

1. 现场设备发生故障,可以通过Shell可以查看设备的故障状态统计信息

2. 能实现串口程序升级(需要Shell+IAP驱动程序支持)

3. 能读写访问参数区,实现对设备参数的本地配置

4. 配置多功能信号指示灯(LED灯可显示65535种信号,同一时刻只能显示一个.

5. 程序开发阶段基于Shell,可以极其方便的调试编写的驱动程序(开发极力推荐),非常好用.

使用特权

评论回复
地板
八层楼|  楼主 | 2019-7-6 12:43 | 只看该作者
二.Shell基础篇
Shell基础程序只有三个文件:

console.h:用于定义STM32用于Shell的实体串口

shell.cshell平台实现主体

shell.h头文件,任意的驱动文件可调用,就像<stdio.h>一样



shell.c目前包含三个部件:

shell模块(必选)Shell模块初始化时已初始化好Led模块

Led模块(必选)Ledx_on(x),Ledx_off(x),Ledx_div(x),函数是对编码信号进行控制,而不是直接对硬件实体控制,这样每个LED实体就像通道一样可以选择非常多的信号源显示.

精密延时模块(可选)启动需要对其初始化,此模块可用于记录时间点,并判断时间是否到(再也不用Delayms()这样的函数浪费效率实现时序了.

使用特权

评论回复
5
八层楼|  楼主 | 2019-7-6 12:43 | 只看该作者
三. 程序文件:
1. console.h
/*********************************Copyright (c)*********************************
**                              
**                                 FIVE工作组
**
**---------------------------------File Info------------------------------------
** File Name:               shell_hal.h
** Last modified Date:      2014/5/26 14:22:35
** Last Version:            V1.0  
** Description:             本地Shell文件接口
**
**------------------------------------------------------------------------------
** Created By:              wanxuncpx
** Created date:            2014/5/26 14:22:34
** Version:                 V2
** Descriptions:            只适合STM32程序
**------------------------------------------------------------------------------
** Libraries:               STM32F10x_StdPeriph_Driver
** version                  V3.5
*******************************************************************************/

/******************************************************************************
更新说明:
******************************************************************************/

/******************************************************************************
*********************************  应 用 资 料 ********************************
******************************************************************************/

#ifndef _SHELL_HAL_
#define _SHELL_HAL_
/******************************************************************************
********************************* 文件引用部分 ********************************
******************************************************************************/
//包含库文件
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"

/******************************************************************************
******************************** 可 配 置 参 数 *******************************
******************************** MNCS_IMAGE图像板 *****************************
******************************************************************************/
/*---------------------*
*     UART端口配置
*----------------------*/
//IO配置
#define CONSOLE                 USART3
#define CONSOLE_TX_PORT         GPIOB
#define CONSOLE_TX_PIN          GPIO_Pin_10
#define CONSOLE_RX_PORT         GPIOB
#define CONSOLE_RX_PIN          GPIO_Pin_11

//时钟配置
#define CONSOLE_GPIO_RCC_INIT() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE)
#define CONSOLE_UART_RCC_INIT() RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE)

//中断优先级
#define CONSOLE_UART_PRIO       7       //建议[0..15]

//中断向量配置
#define CONSOLE_IRQn            USART3_IRQn;
#define CONSOLE_IRQHandler      USART3_IRQHandler

/*---------------------*
*     四个LED定义
*----------------------*/
#define LED0_VALID              1           //非零表示使能对应的LED,0:无效
#define LED0_PORT               GPIOB
#define LED0_PIN                GPIO_Pin_13

#define LED1_VALID              1           //非零表示使能对应的LED,0:无效
#define LED1_PORT               GPIOB
#define LED1_PIN                GPIO_Pin_15

#define LED2_VALID              0           //非零表示使能对应的LED,0:无效
#define LED2_PORT               GPIOA
#define LED2_PIN                GPIO_Pin_11

#define LED3_VALID              0           //非零表示使能对应的LED,0:无效
#define LED3_PORT               GPIOA
#define LED3_PIN                GPIO_Pin_11

#define LED4_VALID              0           //非零表示使能对应的LED,0:无效
#define LED4_PORT               GPIOA
#define LED4_PIN                GPIO_Pin_11

#define LED5_VALID              0           //非零表示使能对应的LED,0:无效
#define LED5_PORT               GPIOA
#define LED5_PIN                GPIO_Pin_11

/*---------------------*
*        时基BASE
*----------------------*/
#define TIMEDly                 TIM4
#define TIMEDly_IRQn            TIM4_IRQn
#define TIMEDly_IRQHandler      TIM4_IRQHandler

//时钟配置            
#define TIMEDly_RCC_INIT()      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

//初始化LGPIO口
#define LEDx_GPIO_RCC_INIT()    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE)
//------------------------------------------------------------------------------

/******************************************************************************
******************************* 以下参数无需更改 ******************************
******************************************************************************/
/*---------------------*
*  注意以下区域无需用户更改
*----------------------*/
#if LED0_VALID
  #define LED0_ON()             (LED0_PORT->BRR  = LED0_PIN)
  #define LED0_OFF()            (LED0_PORT->BSRR = LED0_PIN)
  #define LED0_DIV()            (LED0_PORT->ODR  ^= LED0_PIN)
#else
  #define LED0_ON()             __NOP()
  #define LED0_OFF()            __NOP()
  #define LED0_DIV()            __NOP()
#endif

#if LED1_VALID
  #define LED1_ON()             (LED1_PORT->BRR  = LED1_PIN)
  #define LED1_OFF()            (LED1_PORT->BSRR = LED1_PIN)
  #define LED1_DIV()            (LED1_PORT->ODR ^= LED1_PIN)
#else
  #define LED1_ON()             __NOP()
  #define LED1_OFF()            __NOP()
  #define LED1_DIV()            __NOP()
#endif

#if LED2_VALID
  #define LED2_ON()             (LED2_PORT->BRR  = LED2_PIN)
  #define LED2_OFF()            (LED2_PORT->BSRR = LED2_PIN)
  #define LED2_DIV()            (LED2_PORT->ODR ^= LED2_PIN)
#else
  #define LED2_ON()             __NOP()
  #define LED2_OFF()            __NOP()
  #define LED2_DIV()            __NOP()
#endif  

#if LED3_VALID
  #define LED3_ON()             (LED3_PORT->BRR  = LED3_PIN)
  #define LED3_OFF()            (LED3_PORT->BSRR = LED3_PIN)
  #define LED3_DIV()            (LED3_PORT->ODR ^= LED3_PIN)
#else
  #define LED3_ON()             __NOP()
  #define LED3_OFF()            __NOP()
  #define LED3_DIV()            __NOP()
#endif

#if LED4_VALID
  #define LED4_ON()             (LED4_PORT->BSRR = LED4_PIN)
  #define LED4_OFF()            (LED4_PORT->BRR  = LED4_PIN)
  #define LED4_DIV()            (LED4_PORT->ODR ^= LED4_PIN)
#else
  #define LED4_ON()             __NOP()
  #define LED4_OFF()            __NOP()
  #define LED4_DIV()            __NOP()
#endif

#if LED5_VALID
  #define LED5_ON()             (LED5_PORT->BSRR = LED5_PIN)
  #define LED5_OFF()            (LED5_PORT->BRR  = LED5_PIN)
  #define LED5_DIV()            (LED5_PORT->ODR ^= LED5_PIN)
#else
  #define LED5_ON()             __NOP()
  #define LED5_OFF()            __NOP()
  #define LED5_DIV()            __NOP()
#endif
/******************************************************************************
******************************* printf支持文件 ********************************
******************************************************************************/
/* Private function prototypes -----------------------------------------------*/
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

/******************************************************************************
***********************************   END  ************************************
******************************************************************************/
#endif

使用特权

评论回复
6
八层楼|  楼主 | 2019-7-6 12:44 | 只看该作者
2. shell.h
/*********************************Copyright (c)*********************************
**                              
**                                 FIVE工作组
**
**---------------------------------File Info------------------------------------
** File Name:               shell.h
** Last modified Date:      2014/3/5 15:42:05
** Last Version:            V2   
** Description:             none
**
**------------------------------------------------------------------------------
** Created By:              wanxuncpx
** Created date:            2014/3/5 15:42:11
** Version:                 V2
** Descriptions:            none
**------------------------------------------------------------------------------
** Libraries:               无关
** version                  无关
*******************************************************************************/

/******************************************************************************
更新说明:
******************************************************************************/

/******************************************************************************
*********************************  应 用 资 料 ********************************
******************************************************************************/

#ifndef _SHELL_H_
#define _SHELL_H_
/******************************************************************************
********************************* 文件引用部分 ********************************
******************************************************************************/
#include "stdint.h"         //包含uint8_t等数据类型
#include "stdbool.h"        //包含Bool类型
#include "stdio.h"          //包含printf支持

/******************************************************************************
********************************* 参数宏定义 *********************************
******************************************************************************/
//版本定义
#define SHELL_VER           2       //Shell版本
#ifndef SHELL_LED_MAX               //LED实体数量
  #define SHELL_LED_MAX     4
#endif

//缓冲大小配置
#define SHELL_RX_MAX        (256+32)        //shell指令接收缓冲大小
#define SHELL_TX_MAX        (512)           //shell指令发送缓冲大小

/******************************************************************************
********************************* 数 据 声 明 *********************************
******************************************************************************/
/*---------------------*
*     Shell接收
*----------------------*/
//接收数据
extern volatile uint16_t   shell_rx_rdy;                    //0:空闲,非零:忙,用户读为非零后清零
extern volatile uint8_t    shell_rx_buff[SHELL_RX_MAX+1];   //接收缓冲

/******************************************************************************
********************************* 函 数 声 明 *********************************
******************************************************************************/
/*---------------------*
*    输出函数
*----------------------*/
//调试Shell的接口数量
#if     (6 == SHELL_LED_MAX)
  extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
                                uint16_t led2_cfg,uint16_t led3_cfg,
                                uint16_t led4_cfg,uint16_t led5_cfg);
#elif   (5 == SHELL_LED_MAX)
  extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
                                uint16_t led2_cfg,uint16_t led3_cfg,
                                uint16_t led4_cfg);
#elif   (4 == SHELL_LED_MAX)
  extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
                                uint16_t led2_cfg,uint16_t led3_cfg);
#elif   (3 == SHELL_LED_MAX)
  extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
                                uint16_t led2_cfg);
#elif   (2 == SHELL_LED_MAX)
  extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg);
#elif   (1 == SHELL_LED_MAX)
  extern void shell_GPIO_Config(uint16_t led0_cfg);
#endif

//检测参数合法性
#if ((SHELL_LED_MAX > 6) || (SHELL_LED_MAX == 0))
  #error SHELL_LED_MAX is invaild!
#endif

//初始化Shell
extern void shell_Init(uint32_t baud);          //模块初始化
extern void shell_SendStr(void * ptStr);        //发送以'\0'结束的字符串
extern void shell_SendHex(void * ptHex,uint16_t size);  //发送指定个数的数据

/*---------------------*
*    LEDx测试信号定义
*----------------------*/
extern void Ledx_config(uint8_t led_id,uint16_t msg_id);    //设置LED的配置信号
extern uint16_t Ledx_read(uint8_t led_id);                  //读取LED的配置信号(失败返回0)
extern  void Ledx_on (uint16_t msg_id);             //发送LED开消息
extern  void Ledx_off(uint16_t msg_id);             //发送LED关消息
extern  void Ledx_div(uint16_t msg_id);             //发送LED取反消息

/*---------------------*
*     时基延时函数
*----------------------*/
extern void Delay_LibInit(void);
extern void DlyTime_us(uint16_t us);
extern void DlyTime_ms(uint16_t ms);
extern void DlyWait_base(volatile uint64_t * ptCnt);    //标记为等待的基点时间
extern uint32_t DlyWait_lost(volatile uint64_t * ptCnt);//判断逝去的时间(us)

/*---------------------*
*     辅助判断指令
*----------------------*/
extern bool StrComp(void * buffer,void * StrCmd);   //字符串匹配比较函数

/*---------------------*
*       Shell服务
*----------------------*/
//在main.c函数while()中判断shell_rx_rdy是否为非零,为非零才执行以下程序
extern void Shell_Invalid_Service(void); //指令未处理服务(会处理shell_rx_rdy信号)

/******************************************************************************
***********************************   END  ************************************
******************************************************************************/
#endif

使用特权

评论回复
7
八层楼|  楼主 | 2019-7-6 12:44 | 只看该作者
3.shell.c
/*********************************Copyright (c)*********************************
**                              
**                                 FIVE工作组
**
**---------------------------------File Info------------------------------------
** File Name:               shell.c
** Last modified Date:      2014/3/5 16:43:59
** Last Version:            V2  
** Description:             none
**
**------------------------------------------------------------------------------
** Created By:              wanxuncpx
** Created date:            2014/3/5 16:43:58
** Version:                 V2
** Descriptions:            适合于STM32
**------------------------------------------------------------------------------
** Libraries:               STM32F10x_StdPeriph_Driver
** version                  V3.5
*******************************************************************************/

/******************************************************************************
更新说明:
******************************************************************************/

/******************************************************************************
*********************************  应 用 资 料 ********************************
******************************************************************************/

/******************************************************************************
********************************* 文件引用部分 ********************************
******************************************************************************/
#include "shell.h"      //包含Shell接口文件

//是否使用扩展的Shell接口
#ifdef SHELL_HAL_EXT
  #include "shell_hal.h"    //本地的Shell文件
#else
  #include "console.h"      //标准的Shell文件
#endif

/******************************************************************************
********************************* Shell.h定义 *********************************
******************************************************************************/
/*---------------------*
*     Shell 收发标记
*----------------------*/
volatile uint16_t   shell_rx_rdy = 0;                       //0:空闲,非零:忙
volatile uint8_t    shell_rx_buff[SHELL_RX_MAX+1]="\0";   //接收缓冲

/******************************************************************************
********************************* 本 地 数 据 *********************************
******************************************************************************/
/*---------------------*
*     Shell缓冲定义
*----------------------*/
//接收
static volatile uint16_t    shell_rx_index = 0;             //数据接收标记

//发送
static volatile uint8_t     shell_tx_buff[SHELL_TX_MAX+1]="\0";
static volatile uint16_t    shell_tx_size  = 0;             //0:空闲,非零:忙
static volatile uint16_t    shell_tx_index = 0;             //发送数据标记

/*---------------------*
*     LED控制信号
*----------------------*/
static volatile uint16_t    msg_led_cfg[SHELL_LED_MAX];     //配置信号

/*---------------------*
*    延时模块定义
*----------------------*/
static volatile uint64_t    TimeDlyCnt = 0;                 //用于辅助的延时计数值

/******************************************************************************
********************************* 函 数 声 明 *********************************
******************************************************************************/
/******************************************************************************
/ 函数功能:初始化GPIO口(串口和四个LED灯配置)
/ 修改日期:none
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
#if     (6 == SHELL_LED_MAX)
    void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
                            uint16_t led2_cfg,uint16_t led3_cfg,
                            uint16_t led4_cfg,uint16_t led5_cfg)
#elif   (5 == SHELL_LED_MAX)
    void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
                            uint16_t led2_cfg,uint16_t led3_cfg,
                            uint16_t led4_cfg)
#elif   (4 == SHELL_LED_MAX)
    void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
                            uint16_t led2_cfg,uint16_t led3_cfg)
#elif   (3 == SHELL_LED_MAX)
    void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
                            uint16_t led2_cfg)
#elif   (2 == SHELL_LED_MAX)
    void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg)
#elif   (1 == SHELL_LED_MAX)
    void shell_GPIO_Config(uint16_t led0_cfg)
#endif
{
        GPIO_InitTypeDef GPIO_InitStruct;
       
    /* 配置串口 ---------------------------------------------------------*/
        // 打开在APB2上的GPIO口外设时钟
        CONSOLE_GPIO_RCC_INIT();    //打开GPIO口的时钟

        // 配置TX引脚
        GPIO_InitStruct.GPIO_Pin    = CONSOLE_TX_PIN;
        GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_50MHz;
        GPIO_Init(CONSOLE_TX_PORT,  &GPIO_InitStruct);

        // 配置RX引脚
        GPIO_InitStruct.GPIO_Pin    = CONSOLE_RX_PIN;
        GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IPU;
        GPIO_Init(CONSOLE_RX_PORT,  &GPIO_InitStruct);

    //锁定GPIO口,防止其他更改
    GPIO_PinLockConfig(CONSOLE_TX_PORT,CONSOLE_TX_PIN);
    GPIO_PinLockConfig(CONSOLE_RX_PORT,CONSOLE_RX_PIN);
   
    /* 配置LEDx ---------------------------------------------------------*/
    LEDx_GPIO_RCC_INIT();
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
       
        //根据定义配置四个LED
  #if (SHELL_LED_MAX > 0)
    GPIO_InitStruct.GPIO_Pin    = LED0_PIN;
        GPIO_Init(LED0_PORT,   &GPIO_InitStruct);
        GPIO_PinLockConfig(LED0_PORT,LED0_PIN);
    msg_led_cfg[0] = led0_cfg;
        LED0_OFF();
  #endif
  #if (SHELL_LED_MAX > 1)
    GPIO_InitStruct.GPIO_Pin    = LED1_PIN;
        GPIO_Init(LED1_PORT,   &GPIO_InitStruct);
        GPIO_PinLockConfig(LED1_PORT,LED1_PIN);
        msg_led_cfg[1] = led1_cfg;
        LED1_OFF();
  #endif
  #if (SHELL_LED_MAX > 2)
    GPIO_InitStruct.GPIO_Pin    = LED2_PIN;
        GPIO_Init(LED2_PORT,   &GPIO_InitStruct);
        GPIO_PinLockConfig(LED2_PORT,LED2_PIN);
        msg_led_cfg[2] = led2_cfg;
        LED2_OFF();
  #endif
  #if (SHELL_LED_MAX > 3)
    GPIO_InitStruct.GPIO_Pin    = LED3_PIN;
        GPIO_Init(LED3_PORT,   &GPIO_InitStruct);
        GPIO_PinLockConfig(LED3_PORT,LED3_PIN);
        msg_led_cfg[3] = led3_cfg;
        LED3_OFF();
  #endif
  #if (SHELL_LED_MAX > 4)
    GPIO_InitStruct.GPIO_Pin    = LED4_PIN;
        GPIO_Init(LED4_PORT,   &GPIO_InitStruct);
        GPIO_PinLockConfig(LED4_PORT,LED4_PIN);
        msg_led_cfg[4] = led4_cfg;
        LED4_OFF();
  #endif
  #if (SHELL_LED_MAX > 5)
    GPIO_InitStruct.GPIO_Pin    = LED5_PIN;
        GPIO_Init(LED5_PORT,   &GPIO_InitStruct);
        GPIO_PinLockConfig(LED5_PORT,LED5_PIN);
        msg_led_cfg[5] = led5_cfg;
        LED5_OFF();
  #endif
}

使用特权

评论回复
8
八层楼|  楼主 | 2019-7-6 12:44 | 只看该作者
/******************************************************************************
/ 函数功能:串口初始化,使用中断单字节接收数据
/ 修改日期:none
/ 输入参数:baud 波特率
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void shell_Init(uint32_t baud)
{
    USART_InitTypeDef   USART_InitStructure;
    NVIC_InitTypeDef    NVIC_UART_Cfg;  //UART中断向量
   
    //--------------------------- 先定义好数据结构 ---------------------------
    //定义好USART结构体
    USART_InitStructure.USART_BaudRate      = baud;
    USART_InitStructure.USART_WordLength    = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits      = USART_StopBits_1;
    USART_InitStructure.USART_Parity        = USART_Parity_No ;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode          = USART_Mode_Tx | USART_Mode_Rx;
    USART_InitStructure.USART_BaudRate = USART_InitStructure.USART_BaudRate;    //防止编译报错
   
    //定义好NVIC:UART中断
    NVIC_UART_Cfg.NVIC_IRQChannel = CONSOLE_IRQn;
    NVIC_UART_Cfg.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_UART_Cfg.NVIC_IRQChannelSubPriority = CONSOLE_UART_PRIO;
    NVIC_UART_Cfg.NVIC_IRQChannelCmd = ENABLE;
    NVIC_UART_Cfg.NVIC_IRQChannel = NVIC_UART_Cfg.NVIC_IRQChannel;              //防止编译报错
   
    //模式配置
    //--------------------------- 中断方式收发数据 ----------------------------
    CONSOLE_UART_RCC_INIT();                                //打开USART的时钟
    USART_Cmd(CONSOLE, DISABLE);                            //关闭UART
   
    USART_Init(CONSOLE, &USART_InitStructure);              //初始化串口
   
    USART_ITConfig(CONSOLE, USART_IT_RXNE, ENABLE);
    USART_ITConfig(CONSOLE, USART_IT_IDLE, ENABLE);
   
    USART_Cmd(CONSOLE, ENABLE);
   
    NVIC_Init(&NVIC_UART_Cfg);                              //配置好NVIC
}

使用特权

评论回复
9
八层楼|  楼主 | 2019-7-6 12:45 | 只看该作者
/******************************************************************************
/ 函数功能:Delay延时库初始化(需要1us的计数精度,和50ms的溢出计数)
/ 修改日期:2014/5/1 21:02:58
/ 输入参数:none
/ 输出参数:none
/ 使用说明:(限STM32F40X的TIM2,TIM3,TIM4,TIM5)
******************************************************************************/
void Delay_LibInit(void)
{
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    NVIC_InitTypeDef            NVIC_InitStructure;
   
    //开启TIM2时钟
    TIMEDly_RCC_INIT();

    /* Enable the TIMx gloabal Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                  = TIMEDly_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority       = 0;    //由于是时基,需要使用最高优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd               = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
  
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period    = 65000;
    TIM_TimeBaseStructure.TIM_Prescaler     = (SystemCoreClock/1000000)-1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode    = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIMEDly, &TIM_TimeBaseStructure);
   
    /* TIM Interrupts enable */
    TIM_ITConfig(TIMEDly,TIM_IT_Update, ENABLE);

    /* TIMx enable counter */
    TIM_Cmd(TIMEDly, ENABLE);
}

使用特权

评论回复
10
八层楼|  楼主 | 2019-7-6 12:45 | 只看该作者
/******************************************************************************
/ 函数功能:等待一个us延时
/ 修改日期:2014/5/1 21:02:58
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void DlyTime_us(uint16_t us)
{
   uint64_t this_cnt,over_cnt,tmp_val;
   
    //得到当前的准确时间
    do
    {
        this_cnt = TIMEDly->CNT + TimeDlyCnt;
        if( (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    )
        {
            TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
            TimeDlyCnt  +=  65000;  
        }
        tmp_val = TIMEDly->CNT + TimeDlyCnt;
    }
    while(this_cnt != tmp_val);
    over_cnt = this_cnt + us;       //得到目标延时时间
   
    //延时函数
    do
    {
        if( (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    )
        {
            TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
            TimeDlyCnt  +=  65000;  
        }
        
        this_cnt = TIMEDly->CNT + TimeDlyCnt;
    }
    while(this_cnt < over_cnt);
}

使用特权

评论回复
11
八层楼|  楼主 | 2019-7-6 12:45 | 只看该作者
/******************************************************************************
/ 函数功能:等待一个ms延时
/ 修改日期:2014/5/1 21:02:58
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void DlyTime_ms(uint16_t ms)
{
   uint64_t this_cnt,over_cnt,tmp_val;
   
    //得到当前的准确时间
    do
    {
        this_cnt = TIMEDly->CNT + TimeDlyCnt;
        if( (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    )
        {
            TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
            TimeDlyCnt  +=  65000;  
        }
        tmp_val = TIMEDly->CNT + TimeDlyCnt;
    }
    while(this_cnt != tmp_val);
    over_cnt = this_cnt + (uint32_t)ms*1000;
   
    //延时函数
    do
    {
        if( (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    )
        {
            TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
            TimeDlyCnt  +=  65000;  
        }
        this_cnt = TIMEDly->CNT + TimeDlyCnt;
    }
    while(this_cnt < over_cnt);
}

使用特权

评论回复
12
八层楼|  楼主 | 2019-7-6 12:46 | 只看该作者
/******************************************************************************
/ 函数功能:标记时间起点
/ 修改日期:2014/5/1 21:02:58
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void DlyWait_base(volatile uint64_t * ptCnt)
{
    uint64_t this_cnt,tmp_val;
   
    //得到当前的准确时间
    do
    {
        this_cnt = TIMEDly->CNT + TimeDlyCnt;
        if( (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    )
        {
            TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
            TimeDlyCnt  +=  65000;  
        }
        tmp_val = TIMEDly->CNT + TimeDlyCnt;
    }
    while(this_cnt != tmp_val);
    *ptCnt = this_cnt;
}

使用特权

评论回复
13
八层楼|  楼主 | 2019-7-6 12:46 | 只看该作者
/******************************************************************************
/ 函数功能:检测从起点开始已逝去的时间(最大1个小时)
/ 修改日期:2014/5/1 21:02:58
/ 输入参数:none
/ 输出参数:返回0表示时间到,返回非零表示时间未到
/ 使用说明:none
******************************************************************************/
uint32_t DlyWait_lost(volatile uint64_t * ptCnt)
{
    uint64_t this_cnt,tmp_val;
   
    //得到当前的准确时间
    do
    {
        this_cnt = TIMEDly->CNT + TimeDlyCnt;
        if( (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    &&
            (TIMEDly->SR    & TIM_IT_Update)    )
        {
            TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
            TimeDlyCnt  +=  65000;
        }
        tmp_val = TIMEDly->CNT + TimeDlyCnt;
    }
    while(this_cnt != tmp_val);
   
    //计算已逝去的时间
    if(*ptCnt <= this_cnt)
    {
        tmp_val = this_cnt - *ptCnt;
        if(tmp_val > (65536UL*65536UL-1))
                return (uint32_t)(65536UL*65536UL-1);
        else    return (uint32_t)tmp_val;
    }
    else
    {
        *ptCnt = this_cnt;
        return 0;      
    }
}

使用特权

评论回复
14
八层楼|  楼主 | 2019-7-6 12:46 | 只看该作者
/******************************************************************************
/ 函数功能:中断支持函数(限STM32F40X的TIM2,TIM3,TIM4,TIM5)
/ 修改日期:2014/5/1 21:02:58
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void TIMEDly_IRQHandler(void)
{
    //简单写法
    if( TIMEDly->SR & TIM_IT_Update )
    {
        TIMEDly->SR = (uint16_t)~TIM_IT_Update;
        TimeDlyCnt += 65000;
        //Ledx_div(3);        //时基信号
    }
}

使用特权

评论回复
15
八层楼|  楼主 | 2019-7-6 12:46 | 只看该作者
/******************************************************************************
/ 函数功能:printf支持函数
/ 修改日期:none
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
PUTCHAR_PROTOTYPE
{
    Ledx_on(11);
    /* Loop until the end of transmission */
    while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );
   
    /* Place your implementation of fputc here */
    /* e.g. write a character to the USART */
    CONSOLE->DR = ch;
   
    /* Loop until the end of transmission */
    //while( (CONSOLE->SR & USART_FLAG_TC) == RESET );
    Ledx_off(11);
    return ch;
}

使用特权

评论回复
16
八层楼|  楼主 | 2019-7-6 12:47 | 只看该作者
/******************************************************************************
/ 函数功能:字符串发送函数
/ 修改日期:none
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void shell_SendStr(void * ptAsc)
{                                   //中断方式
    //--------------------------- 中断方式收发数据 ----------------------------
    uint16_t        i,size;
    uint8_t         *ptDst;
    uint8_t const   *ptSrc;     //源数据只读不写
   
    //计算字符串的长度
    ptSrc = (uint8_t const *)ptAsc;
    size  = 0;
    while(*ptSrc++){size++;}
   
    //判断字符串是否超过缓冲
    Ledx_on(11);
    if(size > SHELL_TX_MAX)
    {
        //关闭中断发送方式
        shell_tx_index = 0;
        shell_tx_size  = 0;
        CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //关闭发送完毕中断
        
        ptSrc = (uint8_t const *)ptAsc;
        while(size--)
        {
            while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );
            CONSOLE->DR = *ptSrc++;
        }
        Ledx_off(11);
    }
    else if( !(CONSOLE->CR1 & USART_CR1_TXEIE) )
    {
        //如果未启用非空中断则,启用非空中断发送数据
        //复制数据
        ptDst = (uint8_t *)shell_tx_buff;
        ptSrc = (uint8_t const *)ptAsc;
        for(i=0; i<size; i++)
            *ptDst++ = *ptSrc++;
        
        //启动发送中断
        shell_tx_index = 0;
        shell_tx_size  = size;
        CONSOLE->CR1 |= USART_CR1_TXEIE;        //启动发送非空中断        
    }
}

使用特权

评论回复
17
八层楼|  楼主 | 2019-7-6 12:47 | 只看该作者
/******************************************************************************
/ 函数功能:发送Hex数据函数
/ 修改日期:none
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void shell_SendHex(void * ptHex,uint16_t size)
{                                  //中断方式
    //--------------------------- 中断方式收发数据 ----------------------------
    uint16_t        i;
    uint8_t         *ptDst;
    uint8_t const   *ptSrc;     //源数据只读不写

    Ledx_on(11);
    if(size > SHELL_TX_MAX)
    {
        //关闭中断发送方式
        shell_tx_index = 0;
        shell_tx_size  = 0;
        CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //关闭发送完毕中断
        
        //直接发送数据
        ptSrc = (uint8_t const *)ptHex;
        while(size--)
        {
            while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );
            CONSOLE->DR = *ptSrc++;
        }
        Ledx_off(11);
    }
    else if( !(CONSOLE->CR1 & USART_CR1_TXEIE) )
    {
        //如果未启用非空中断则,启用非空中断发送数据
        //复制数据
        ptDst = (uint8_t *)shell_tx_buff;
        ptSrc = (uint8_t const *)ptHex;   
        for(i=0; i<size; i++)
            *ptDst++ = *ptSrc++;
        
        //启动发送中断
        shell_tx_index = 0;
        shell_tx_size  = size;
        CONSOLE->CR1 |= USART_CR1_TXEIE;        //启动发送非空中断     
    }
}

使用特权

评论回复
18
八层楼|  楼主 | 2019-7-6 12:47 | 只看该作者
/******************************************************************************
/ 函数功能:中断服务程序
/ 修改日期:none
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
void CONSOLE_IRQHandler(void)
{
    uint8_t     rxd_reg,txd_reg;
    uint16_t    isr_reg;
                                       //中断配置
    //--------------------------- 中断方式收发数据 ----------------------------
    isr_reg = CONSOLE->SR;
    //接收中断
    if( (CONSOLE->CR1 & USART_CR1_RXNEIE) && (isr_reg & USART_SR_RXNE) )
    {
        rxd_reg = CONSOLE->DR;
        Ledx_on(12);
        if(shell_rx_rdy)shell_rx_index = 0;     //忙模式收到字节,重置接收指针
        else
        {
            if( shell_rx_index < SHELL_RX_MAX)
            {
                shell_rx_buff[shell_rx_index] = rxd_reg;
                shell_rx_index++;
            }
            else
            {
                shell_rx_index = 0;
                Ledx_off(12);   
            }
        }
    }
   
    if( (CONSOLE->CR1 & USART_CR1_IDLEIE) && (isr_reg & USART_SR_IDLE) )
    {
        CONSOLE->SR;
        CONSOLE->DR;
        if(shell_rx_rdy)shell_rx_index = 0;     //忙模式收到空闲,重置接收指针
        else
        {
            if( (shell_rx_index >=2) && ('\r' == shell_rx_buff[shell_rx_index-2]) &&
                ('\n' == shell_rx_buff[shell_rx_index-1])   )       //以"\r\n"结尾
            {
                shell_rx_rdy = shell_rx_index;
                shell_rx_index = 0;
                Ledx_off(12);
            }
            else if( (shell_rx_index > 0) && ('\b' == shell_rx_buff[shell_rx_index-1]) )  //以\b结尾
            {
                shell_rx_index = shell_rx_index <2? 0:shell_rx_index-2;
                printf(" \b");      //发送辅助删除        
            }
        }
    }
   
    //发送非空中断   
    if( (CONSOLE->CR1 & USART_CR1_TXEIE) && (isr_reg & USART_SR_TXE ) )
    {
        if(shell_tx_size && (shell_tx_index < shell_tx_size) )
        {
            txd_reg = shell_tx_buff[shell_tx_index++];
            CONSOLE->DR = txd_reg;  //发送数据
        }
        else
        {
            //关闭非空中断
            shell_tx_index = 0;
            shell_tx_size = 0;
            CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //关闭发送完毕中断
            Ledx_off(11);
        }         
    }
}

使用特权

评论回复
19
八层楼|  楼主 | 2019-7-6 12:48 | 只看该作者
/******************************************************************************
/ 函数功能:指令(ASCII或HEX指令)未处理消息回执
/ 修改日期:2013/9/12 20:25:45
/ 输入参数:none
/ 输出参数:none
/ 使用说明:一字节一字节接收数据,拼装为指令
******************************************************************************/
void Shell_Invalid_Service(void)
{
    int         tx_len,i,led_id,msg_id;
    uint8_t *   ptSrc;
    uint8_t *   ptDst;
    uint8_t     tmp_buff[64];
   
    //指令识别
    if(2 > shell_rx_rdy)
    {
        shell_rx_buff[0]  = 0;
        return;
    }
    else if( ('\r' == shell_rx_buff[shell_rx_rdy-2]) && ('\n' == shell_rx_buff[shell_rx_rdy-1]) )
    {
        ptSrc = (uint8_t *)shell_rx_buff;
        if(2 == shell_rx_rdy)
        {
            //填写数据
            tx_len = (uint16_t)sprintf((void *)tmp_buff,"\r\nAT:OK!\r\n");
        
            //发送数据
            shell_SendHex(tmp_buff,tx_len);     //发送数据   
        }
        else if(StrComp(ptSrc,"led rd\r\n"))   //显示LED的信号配置
        {
            //填写数据
            tx_len = (uint16_t)sprintf((void *)tmp_buff,
          #if     (6 == SHELL_LED_MAX)
                "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d  LED4=%d  LED5=%d\r\n",
                msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],
                msg_led_cfg[3],msg_led_cfg[4],msg_led_cfg[5]);
          #elif   (5 == SHELL_LED_MAX)
                "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d  LED4=%d\r\n",
                msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],
                msg_led_cfg[3],msg_led_cfg[4]);
          #elif   (4 == SHELL_LED_MAX)
                "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d\r\n",
                msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],
                msg_led_cfg[3]);
          #elif   (3 == SHELL_LED_MAX)
                "->LED0=%d  LED1=%d  tLED2=%d\r\n",
                msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2]);
          #elif   (2 == SHELL_LED_MAX)
                "->LED0=%d  LED1=%d\r\n",
                msg_led_cfg[0],msg_led_cfg[1]);
          #elif   (1 == SHELL_LED_MAX)
                "->LED0=%d\r\n",
                msg_led_cfg[0]);
          #endif        
            //发送数据
            shell_SendHex(tmp_buff,tx_len);     //发送数据        
        }
        else if(StrComp(ptSrc,"led wr "))      //设置LED的信号配置
        {
            if(2 != sscanf((void *)ptSrc,"%*s%*s%d=%d",&led_id,&msg_id) )goto ERROR_LOOP;
            if( (led_id>(SHELL_LED_MAX-1)) || (msg_id >65535) )goto ERROR_LOOP;

            Ledx_config((uint8_t)led_id,(uint16_t)msg_id);  //配置信号
            //填写数据
            tx_len = (uint16_t)sprintf((void *)tmp_buff,
                "->LED[%d]_Msg=%d\r\n",led_id,msg_led_cfg[led_id]);

            //发送数据
            shell_SendHex(tmp_buff,tx_len);     //发送数据   
        }
        else goto ERROR_LOOP;
    }
    else
    {
ERROR_LOOP:
        //填写指令码
        tx_len = (uint16_t)sprintf((void *)tmp_buff,"\r\nAT: Cmd Error:\t\"");
        
        //计算地址,填写数据,填写尾部
        ptDst = tmp_buff + tx_len;
        ptSrc = (uint8_t *)shell_rx_buff;
        if(shell_rx_rdy > 32)
        {
            for(i=0; i<32; i++)
            {
                if( (*ptSrc > 126) || (*ptSrc < 32) )
                {
                    *ptDst++ = '?';
                     ptSrc++;   
                }
                else
                {
                    *ptDst++ = *ptSrc++;
                }
            }
            *(ptDst-2) = '-';
            *(ptDst-1) = '>';
            tx_len += 32;
        }
        else
        {
            for(i=0; i<shell_rx_rdy; i++)
            {
                *ptDst++ = *ptSrc++;
                tx_len++;
            }
            *(ptDst-2) = '<';
            *(ptDst-1) = '-';
        }
        tx_len += (uint16_t)sprintf((void *)ptDst,"\"\r\n");
  
        //发送数据
        shell_SendHex(tmp_buff,tx_len);  //发送数据
    }
   
    //清除数据返回程序
    shell_rx_buff[0]  = 0;
    shell_rx_rdy      = 0;
}

使用特权

评论回复
20
八层楼|  楼主 | 2019-7-6 12:48 | 只看该作者
/******************************************************************************
/ 函数功能:字符串测试匹配指令
/ 修改日期:2014/3/5 19:30:22
/ 输入参数:none
/ 输出参数:none
/ 使用说明:none
******************************************************************************/
bool StrComp(void * buffer,void * StrCmd)
{
    uint8_t i;
    uint8_t * ptBuf;
    uint8_t * ptCmd;
   
    ptBuf = (uint8_t *)buffer;
    ptCmd = (uint8_t *)StrCmd;
    for(i=0; i<255; i++)
    {
        if(ptCmd[i])
        {
            if(ptBuf[i] != ptCmd[i])return false;
        }
        else
        {
            if(i)return i;
            else return false;   
        }
    }
    return false;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

91

主题

4146

帖子

2

粉丝