STM32库函数编程

catalogue

1. 基于标准外设库的软件开发
2. 基于固件库实现串口输出(发送)程序
3. 红外接收实验

1. 基于标准外设库的软件开发

0x1: STM32标准外设库概述

STM32标准外设库之前的版本也称固件函数库或简称固件库(即操作片外固件的代码集合),是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化,顺便提一句,arduino之所以入门容易开发简单就是因为我们很多时候是要"面向固件库编程",很多复杂的外设操作都通过简单的API调用就完成了
ST公司2007年10月发布了V1.0版本的固件库,MDK ARM3.22之前的版本均支持该库。2008年6月发布了V2.0版的固件库,从2008年9月推出的MDK ARM3.23版本至今均使用V2.0版本的固件库。V3.0以后的版本相对之前的版本改动较大

0x2: 使用标准外设库开发的优势

使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC等等的所有标准外设。对应的C源代码只是用了最基本的C编程的知识,所有代码经过严格测试,易于理解和使用,并且配有完整的文档,非常方便进行二次开发和应用

0x3: STM32F10XXX标准外设库结构与文件描述

表 5?4 STM32F10XXX V3.4标准外设库文件夹描述


STM32F10x_StdPeriph_Lib_V3.4.0


_htmresc


本文件夹包含了所有的html页面资源


Libraries


CMSIS微控制器软件接口标准(CMSIS:Cortex Microcontroller Software Interface Standard)


是 Cortex-M 处理器系列的与供应商无关的软件抽象层。 使用CMSIS,可以为处理器和外设实现一致且简单的软件接口,从而简化软件的重用


STM32F10x_StdPeriph_Driver


inc


标准外设库驱动头文件


src


标准外设库驱动源文件


Project


Examples


标准外设库驱动的完整例程


Template


MDK-ARM


KEIL RVMDK的项目模板示例


RIDE


Raisonance RIDE的项目模板示例


EWARM


IAR EWARM的项目模板示例


Utilities


STM3210-EVAL


本文件夹包含了用于STM3210B-EVAL和STM3210E-EVAL评估板的专用驱动

标准外设库的第一部分是CMSIS 和STM32F10x_StdPeriph_Driver,CMSIS 是独立于供应商的Cortex-M 处理器系列硬件抽象层,为芯片厂商和中间件供应商提供了简单的处理器软件接口,简化了软件复用工作,降低了Cortex-M 上操作系统的移植难度,并减少了新入门的微控制器开发者的学习曲线和新产品的上市时间。STM32F10x_StdPeriph_Driver则包括了分别对应包括了所有外设对应驱动函数,这些驱动函数均使用C语言编写,并提供了统一的易于调用的函数接口,供开发者使用。Project文件夹中则包括了ST官方的所有例程和基于不同编译器的项目模板,这些例程是学习和使用STM32的重要参考。Utilities包含了相关评估板的示例程序和驱动函数,供使用官方评估板的开发者使用,很多驱动函数同样可以作为学习的重要参考

0x4: STM32F10xxx标准外设库体系结构


文件名


功能描述


具体功能说明


core_cm3.h

core_cm3.c


Cortex-M3内核及其设备文件


访问Cortex-M3内核及其设备:NVIC,SysTick等

访问Cortex-M3的CPU寄存器和内核外设的函数


stm32f10x.h


微控制器专用头文件


这个文件包含了STM32F10x全系列所有外设寄存器的定义(寄存器的基地址和布局)、位定义、中断向量表、存储空间的地址映射等


system_stm32f10x.h

system_stm32f10x.c


微控制器专用系统文件


函数SystemInit,用来初始化微控制器

函数Sysem_ExtMemCtl,用来配置外部存储器控制器。它位于文件startup_stm32f10x_xx.s /.c,在跳转到main前调用

SystemFrequncy,该值代表系统时钟频率


startup_stm32f10x_Xd.s


编译器启动代码


微控制器专用的中断处理程序列表(与头文件一致)

弱定义(Weak)的中断处理程序默认函数(可以被用户代码覆盖) 该文件是与编译器相关的


stm32f10x_conf.h


固件库配置文件


通过更改包含的外设头文件来选择固件库所使用的外设,在新建程序和进行功能变更之前应当首先修改对应的配置。


stm32f10x_it.h

stm32f10x_it.c


外设中断函数文件


用户可以相应的加入自己的中断程序的代码,对于指向同一个中断向量的多个不同中断请求,用户可以通过判断外设的中断标志位来确定准确的中断源,执行相应的中断服务函数。


stm32f10x_ppp.h

stm32f10x_ppp.c


外设驱动函数文件


包括了相关外设的初始化配置和部分功能应用函数,这部分是进行编程功能实现的重要组成部分。


Application.c


用户文件


用户程序文件,通过标准外设库提供的接口进行相应的外设配置和功能设计。

0x5: 基于CMSIS标准的软件架构
对于ARM公司来说,一个ARM内核往往会授权给多个厂家,生产种类繁多的产品,如果没有一个通用的软件接口标准,那么当开发者在使用不同厂家的芯片时将极大的增加了软件开发成本,因此,ARM与Atmel、IAR、Keil、hami-nary Micro、Micrium、NXP、SEGGER和ST等诸多芯片和软件厂商合作,将所有Cortex芯片厂商产品的软件接口标准化,制定了CMSIS标准。此举意在降低软件开发成本,尤其针对新设备项目开发,或者将已有软件移植到其他芯片厂商提供的基于Cortex处理器的微控制器的情况。有了该标准,芯片厂商就能够将他们的资源专注于产品外设特性的差异化,并且消除对微控制器进行编程时需要维持的不同的、互相不兼容的标准的需求,从而达到降低开发成本的目的

基于CMSIS标准的软件架构(或者叫固件库架构)主要分为以下4层

1. 用户应用层
2. 操作系统及中间件接口层
3. CMSIS层: CMSIS层起着承上启下的作用
    1) 一方面该层对硬件寄存器层进行统一实现,屏蔽了不同厂商对Cortex-M系列微处理器核内外设寄存器的不同定义
    2) 另一方面又向上层的操作系统及中间件接口层和应用层提供接口,简化了应用程序开发难度,使开发人员能够在完全透明的情况下进行应用程序开发。也正是如此,CMSIS层的实现相对复杂
4. 硬件寄存器层

0x6: 使用方式

在实际开发过程中,根据应用程序的需要,可以采取2种方法使用标准外设库(StdPeriph_Lib)

1. 使用外设驱动: 这时应用程序开发基于外设驱动的API(应用编程接口)。用户只需要配置文件"stm32f10x_conf.h",并使用相应的文件例如"stm32f10x_ppp.h/.c"即可
2. 不使用外设驱动: 这时应用程序开发基于外设的寄存器结构和位定义文件(需要了解单片机的大量硬件、引脚细节)

标准外设库(StdPeriph_Lib)支持STM32F10xxx系列全部成员:大容量,中容量和小容量产品,实际开发中根据使用的STM32产品具体型号,用户可以通过文件"stm32f10x.h"中的预处理define或者通过开发环境中的全局设置来配置标准外设库(StdPeriph_Lib),一个define对应一个产品系列

STM32F10x_LD:STM32小容量产品
STM32F10x_MD:STM32中容量产品
STM32F10x_HD:STM32大容量产品

在库文件中这些define的具体作用范围是

1. 文件"stm3210f.h"中的中断IRQ定义
2. 启动文件中的向量表,小容量,中容量,大容量产品各有一个启动文件
3. 外设存储器映像和寄存器物理地址
4. 产品设置: 外部晶振(HSE)的值等
5. 系统配置函数

因此通过宏定义这种方式,可以使标准外设库适用于不同系列的产品,同时也方便与不同产品之间的软件移植,极大的方便了软件的开发
0x7: 命名规范

标准外设库中的主要外设均采用了缩写的形式,通过这些缩写可以很容易的辨认对应的外设。


缩写


外设/单元


ADC


模数转换器


BKP


备份寄存器


CAN


控制器局域网模块


CEC

 

CRC


CRC计算单元


DAC


数模转换器


DBGMCU


调试支持


DMA


直接内存存取控制器


EXTI


外部中断事件控制器


FLASH


闪存存储器


FSMC


灵活的静态存储器控制器


GPIO


通用输入输出


I2C


I2C接口


IWDG


独立看门狗


PWR


电源/功耗控制


RCC


复位与时钟控制器


RTC


实时时钟


SDIO


SDIO接口


SPI


串行外设接口


TIM


定时器


USART


通用同步/异步收发器


WWDG


窗口看门狗

标准外设库遵从以下命名规则 PPP表示任一外设缩写,例如:ADC。源程序文件和头文件命名都以“stm32f10x_”作为开头,例如:stm32f10x_conf.h
外设函数的命名以该外设的缩写加下划线为开头。每个单词的第一个字母都由英文字母大写书写,例如:SPI_SendData。在函数名中,只允许存在一个下划线,用以分隔外设缩写和函数名的其它部分。对于函数命名

Relevant Link:

http://baike.baidu.com/link?url=X3kL65ER2yug2m-_XhgXTggAd7uH7VCnyhdaJ2ddxYt-Nj8oqB46tWDhNngqyrPnuAzzs8wJe56NzIJi-6zWWa
http://www.cnblogs.com/emouse/archive/2011/11/29/2268441.html

2. 基于固件库实现串口输出(发送)程序

0x1: 关键库函数

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
发送函数,它告诉我们很重要的一点,那就是串口是以"位"来传输的

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
用它来得知串口的状态 

0x2: 参考printf函数编写串口发送函数(自定义一个完全脱库标准C库的新函数)

#include <stdio.h>
#include <stdarg.h>

/*************************************************
* Function Name  : USART1_printf
* Description    :
* Input          :
* Output         : NONE
* Return         : NONE
*************************************************/
void USART1_printf (char *fmt, ...)
{
  char buffer[CMD_BUFFER_LEN+1];
  u8 i = 0; 

  va_list arg_ptr;
  va_start(arg_ptr, fmt);
  vsnprintf(buffer, CMD_BUFFER_LEN+1, fmt, arg_ptr);
  while ((i < CMD_BUFFER_LEN) && buffer[i])
  {
    USART_SendData(USART1, (u8) buffer[i++]);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
  }
  va_end(arg_ptr);
}

/*************************************************
* Function Name  : USART1_SendData
* Description    : 串口1发送
* Input          : char *Buffer
* Output         : NONE
* Return         : NONE
*************************************************/
void USART1_SendData(char *Buffer)
{
  u8 Counter = 0;
  while( (Counter == 0) || (Buffer[Counter] != 0) ) //条件...
  {
    USART_SendData(USART1, Buffer[Counter++]);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  }
}

0x3: Code

/*----------------------------------------------------------------------------
 * Name:    Hello.c
 * Purpose: Hello World Example
 * Note(s):
 *----------------------------------------------------------------------------
 * This file is part of the uVision/ARM development tools.
 * This software may only be used under the terms of a valid, current,
 * end user licence from KEIL for a compatible version of KEIL software
 * development tools. Nothing else gives you the right to use this software.
 *
 * This software is supplied "AS IS" without warranties of any kind.
 *
 * Copyright (c) 2012 Keil - An ARM Company. All rights reserved.
 *----------------------------------------------------------------------------*/

#include <stdio.h>               /* prototype declarations for I/O functions  */
#include <stm32f10x.h>           /* STM32F10x definitions                     */
#include <stm32f10x_usart.h>
#include <stdarg.h>
#include <string.h>

#define CMD_BUFFER_LEN 64u 

static void delayms(int cnt){
    int i;
    while(cnt--)
        for (i=0; i<7333; i++);
}

void USART2_printf (char *fmt, ...)
{
    char buffer[CMD_BUFFER_LEN+1] = {0};
    u8 i = 0;
    int len = 0;
    va_list arg_ptr;

    memset(buffer, ‘\x00‘, CMD_BUFFER_LEN+1);

    len = strlen(fmt) + 1;
    va_start(arg_ptr, fmt);
    vsnprintf(buffer, len, fmt, arg_ptr);
    while ((i < len) && buffer[i] != ‘\x00‘) {
        USART_SendData(USART1, (u8) buffer[i++]);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
            ;
    }
    va_end(arg_ptr);
}

extern void SER_Init(void);                                   /* see Serial.c */

/*----------------------------------------------------------------------------
  main program
 *----------------------------------------------------------------------------*/
int main (void)  {               /* execution starts here                     */

  SER_Init ();                   /* initialize the serial interface           */

  USART2_printf ("Hello World\n");      /* the ‘printf‘ function call                */

  while (1) {                    /* An embedded program does not stop and     */
    USART2_printf ("Hello World\n");  /* ... */                 /* never returns. We use an endless loop.    */
        delayms(3000);
  }                              /* Replace the dots (...) with your own code.*/

}

使用64字节的缓冲数组保存需要发送的数据,然后通过while循环逐byte发送往Terminal终端

为了显示方便,还可以加上sleep函数

static void delayms(int cnt){
    int i;
    while(cnt--)
        for (i=0; i<7333; i++);
}

需要明白的,我们从指令层面看while循环,由于指令周期、机器周期都是可时间量化的,因此可以用while来实现spin CPU空转,即sleep

Relevant Link:

http://www.cnblogs.com/mocet/p/stm32f10x_usart_InputOutout_Function_Design_1.html

3. 红外接收实验

二进制脉冲码的形式有多种,其中最为常见的是PWM码(脉冲宽度调制码)和PPM码(脉冲位置调制码,脉冲串之间的时间间隔来实现信号调制),如果要开发红外接收设备,一定要知道红外发射器(例如遥控器)的编码方式和载波频率,我们才可以选取一体化红外接收头和制定解码方案

/**********************************************************************************
*
***********************************************************************************/
#include "stm32f10x.h"
#include "stm32f10x_exti.h"
//#include "stm8s_beep.h"
#include "stm32f10x_systick.h"

#define    LED1_0      GPIOD->BRR  = 0x00000100
#define    LED2_0      GPIOD->BRR  = 0x00000200
#define    LED3_0      GPIOD->BRR  = 0x00000400
#define    LED4_0      GPIOD->BRR  = 0x00000800
#define    LED1_1      GPIOD->BSRR = 0x00000100
#define    LED2_1      GPIOD->BSRR = 0x00000200
#define    LED3_1      GPIOD->BSRR = 0x00000400
#define    LED4_1      GPIOD->BSRR = 0x00000800
#define    IR_Hongwai_0         GPIOE->BRR  = 0x00000004   //???????
#define    IR_Hongwai_1         GPIOE->BSRR = 0x00000004   //???????
#define    IR_Hongwai_x   GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2)  //????????
unsigned int TimeByte;
volatile unsigned int IR_Tireafg[4] = {0, 0, 0, 0};
//unsigned int IR_xidwrit[8] = {0, 0, 0, 0, 0, 0 ,0, 0};

/*
*   GPIO???????
*/
void GPIO_InitStructReadtempCmd(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;     //??GPIO??
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;    //?????????
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;   //??????50MHZ
GPIO_Init(GPIOE, &GPIO_InitStruct);      //???????
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;   //??????????
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
}

/*
*   ?????????
*/
void RCC_APB2PeriphReadtempyCmd(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //??GPIOB????
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);  //??GPIOE????
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);  //??GPIOD????
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);  //??AFIO????????
}
/*
* ?????????Count1 * 10us
*/
unsigned int IR_HongwaiRead_LSB_Cmd()
{
unsigned int Count1 = 0;     //??????
IR_Hongwai_0;        //???????
do           //?????
  {
   Count1++;       //?????1
   Delay_10us(1);      //??10us
  }  while(IR_Hongwai_x == 0);  //???????????????????????

return(Count1);        //????????
}
/*
* ?????????Count2 * 10us
*/
unsigned int IR_HongwaiRead_MSB_Cmd()
{
unsigned int Count2 = 0;     //??????
IR_Hongwai_1;        //???????
do           //?????
  {
   Count2++;       //?????1
   Delay_10us(1);      //??10us
  }  while(IR_Hongwai_x == 1);  //???????????????????????
return(Count2);
}

/*
*   ????
*/
int main(void)
{
SystemInit();        //?????????72M??
SYSTICK_InitStructReadTCmd();    //???SysTick??????
RCC_APB2PeriphReadtempyCmd();    //????????????
GPIO_InitStructReadtempCmd();    //???GPIO???????
EXTI_InitStructReadtempCmd();    //???EXTI???????
NVIC_InitStructReadtempCmd();    //???NVIC???????
while(1)
{

}
}
/*
*   EXTI?????????
*/
void EXTI2_IRQHandler(void)
{
unsigned char i = 0;
unsigned int Countline2 = 0;
IR_Hongwai_1;
Countline2 = IR_HongwaiRead_LSB_Cmd();   //?????? 9ms??
if((Countline2 < 286) || (Countline2 > 305)) //??8694us ??9272us ????????
{
  return;
}
Countline2 = IR_HongwaiRead_MSB_Cmd();   //?????? 4.5ms??
if((Countline2 < 138) || (Countline2 > 155)) //??4195us ??4712us ????????
{
  return;
}
TimeByte = 0;
for(i = 1; i < 14; i++)
{
  TimeByte = TimeByte >> 1;
  Countline2 = IR_HongwaiRead_LSB_Cmd();    //?????0.56 ??
  if((Countline2 < 14) || (Countline2 > 22)) //??425us ??851us ????????
  {
   return;
  }

  Countline2 = IR_HongwaiRead_MSB_Cmd();    //?????0.56??
  if((Countline2 < 14) || (Countline2 > 65)) //??425us ??1793us ????????
  {
   return;
  }
  if( Countline2 > 50)    //???????1300us?1???0
  {
   TimeByte |= 0x80;    //?1
  }
}
  IR_Tireafg[0] = TimeByte;
  TimeByte = 0; 

for(i = 14; i < 27; i++)
{
  TimeByte = TimeByte >> 1;
  Countline2 = IR_HongwaiRead_LSB_Cmd();
  if((Countline2 < 14) || (Countline2 > 22))
  {
   return;
  }

  Countline2 = IR_HongwaiRead_MSB_Cmd();
  if((Countline2 < 14) || (Countline2 > 65))
  {
   return;
  }
  if( Countline2 > 50)
  {
   TimeByte |= 0x80;
  }
}
  IR_Tireafg[1] = TimeByte;
  TimeByte = 0;

for(i = 27; i < 35; i++)
{
  TimeByte = TimeByte >> 1;
  Countline2 = IR_HongwaiRead_LSB_Cmd();
  if((Countline2 < 14) || (Countline2 > 22))
  {
   return;
  }

  Countline2 = IR_HongwaiRead_MSB_Cmd();
  if((Countline2 < 14) && (Countline2 > 65))
  {
   return;
  }
  if( Countline2 > 50)
  {
   TimeByte |= 0x80;
  }
}
  IR_Tireafg[2] = TimeByte;
  TimeByte = 0;

for(i = 35; i < 43; i++)
{
  TimeByte = TimeByte >> 1;
  Countline2 = IR_HongwaiRead_LSB_Cmd();
  if((Countline2 < 14) || (Countline2 > 22))
  {
   return;
  }

  Countline2 = IR_HongwaiRead_MSB_Cmd();
  if((Countline2 < 14) || (Countline2 > 65))
  {
   return;
  }
  if( Countline2 > 52)
  {
   TimeByte |= 0x80;
  }
}
  IR_Tireafg[3] = TimeByte;
//************************?????????***************************************//
  /* if(IR_Tireafg[0]!= 0x11A)
      {
        return;
    }   */        

//************************?????????***************************************//

/*  do
    {
     if(IR_Tireafg[2] == ~IR_Tireafg[3])
     {
      flag = 0;
     }
    } while(flag == 1);    */
/*   if(IR_Tireafg[2] != ~IR_Tireafg[3])
    {
     flag = 0;
    }    */

//************************??????LED??**************************************//
    switch  (IR_Tireafg[2])
    {
     case         0x00:   //?? 0
         LED1_1; LED2_0; LED3_0; LED4_0;
         break; 

     case         0x01:    //?? 1
         LED1_0; LED2_1; LED3_0; LED4_0;
         break; 

     case         0x02:   //?? 2
         LED1_0; LED2_0; LED3_1; LED4_0;
         break; 

     case         0x03:   //?? 3
         LED1_0; LED2_0; LED3_0; LED4_1;
         break;
     case         0x04:   //?? 4
         LED1_0; LED2_0; LED3_1; LED4_0;
         break;
     case         0x05:   //?? 5
         LED1_0; LED2_1; LED3_0; LED4_0;
         break;
     case         0x06:   //?? 6
         LED1_1; LED2_0; LED3_0; LED4_0;
         break;
     case         0x07:   //?? 7
         LED1_1; LED2_0; LED3_1; LED4_0;
         break;
     case         0x08:   //?? 8
         LED1_1; LED2_0; LED3_0; LED4_1;
         break;

     case         0x09:   //?? 9
         LED1_0; LED2_1; LED3_0; LED4_1;
         break;
     case         0x15:   //???
         LED1_0; LED2_1; LED3_1; LED4_0;
         break;
     case         0x1C:   //???
         LED1_0; LED2_0; LED3_0; LED4_0;
         break;

     case         0x14:   //OSD?
         LED1_1; LED2_1; LED3_0; LED4_0;
         break; 

     case         0x0E:   //RECALL?
         LED1_0; LED2_0; LED3_1; LED4_1;
         break; 

     case         0x19:   //SLEEP?
         LED1_1; LED2_1; LED3_1; LED4_0;
         break; 

     case         0x0A:   //A/C?
         LED1_0; LED2_1; LED3_1; LED4_1;
         break; 

     case         0x0F:   //TV/AV?
         LED1_1; LED2_1; LED3_1; LED4_1;
         break; 

     case         0x13:   //PP?
         LED1_1; LED2_0; LED3_1; LED4_0;
         break; 

     case         0x0C:   //GAME?
         LED1_0; LED2_1; LED3_1; LED4_1;
         break; 

     case         0x1E:   //V-?
         LED1_1; LED2_1; LED3_1; LED4_0;
         break; 

     case         0x1F:   //V+?
         LED1_0; LED2_0; LED3_1; LED4_0;
         break;  

     case         0x1B:   //P+?
         LED1_0; LED2_0; LED3_0; LED4_1;
         break;  

     case         0x1A:   //P-?
         LED1_1; LED2_0; LED3_0; LED4_0;
         break;  

     case         0x10:   //MENU?
         LED1_0; LED2_1; LED3_0; LED4_0;
         break;   

      default  :     break;    

    }
// Beep_lookCmd();          //??????
  EXTI_ClearITPendingBit(EXTI_Line2);  //??EXTI2???????
}  

Relevant Link:

http://www.iqiyi.com/w_19rrdz9g91.html#curid=5449021609_7b2174ee370808596288e2209eef0b75
http://bbs.21ic.com/icview-243059-1-1.html
http://wenku.baidu.com/view/2d0b4636a32d7375a417802e.html
http://blog.csdn.net/houqi02/article/details/51585551
http://bbs.21ic.com/icview-649262-1-1.html
http://wenku.baidu.com/link?url=F4r-R2rp-cF8lw7zSxuLYVWRoLdXeCQYt2Kf4hO9Kb7JMe1n7eOxkY-5t4Ar3990U5EmoungBQCyGFJitjsFqSSId5joGVgND6gQntg0ipO

Copyright (c) 2016 LittleHann All rights reserved

时间: 2024-12-15 12:18:45

STM32库函数编程的相关文章

STM32库函数实现方法及使用

一.概述 1.调用STM32库函数配置与直接配置寄存器 ① 直接配置寄存器 使用过51单片机的朋友都知道为了将IO口配置成某种特殊功能或者配置中断控制,我们先将需要如下步骤: 根据需要配置功能计算值---->直接写入寄存器 ② 调用STM32库函数配置 定义一个配置结构体变量---->根据配置功能依次给这个结构体变量的成员赋值----->将结构体变量的地址传入库函数,并调用STM32库函数实现配置 其中最后一个步骤的"调用STM32库函数",实际上就是将配置结果写入寄

如何快速上手使用STM32库函数

一.背景 如前文所述,利用标准库函数的好处在于,可以快速开发,不用去对着数据手册,小心翼翼的一位一位的配置那些繁复的寄存器,因为这些工作意法半导体已经找了一些顶级的工程师帮你做了,杰作既是其库函数.当然,有些代码考虑到低功耗,或者需要极小的ROM,就不能使用库函数,而这即是通常说的,"高度定制化",牺牲开发时间来获取更高代码效率,这个需要自己权衡. 本文以STM32之DMA库函数为例,即如何快速使用STM32库函数做个简述及记录. 二.正文 首先去官网或者论坛下载STM32的官方库,解

STM32库函数void USART_SendData的缺陷和解决方法

void USART_SendData()函数在快速发送时存在问题 有丢数据的可能 转自https://blog.csdn.net/qq_27114397/article/details/50601548 STM32库函数void USART_SendData的缺陷和解决方法使用USART_SendData()函数非连续发送单个字符是没有问题的:当连续发送字符时(两个字符间没有延时),就会发现发送缓冲区有溢出现象.若发送的数据量很小时,此时串口发送的只是最后一个字符,当发送数据量大时,就会导致发

STM32库函数是怎么封装底层寄存器的

固件库首先将各个设备所有寄存器的配置字进行预先定义,然后封装在结构或枚举变量中,待用户调用对应的固件库函数时,会根据用户传入的参数从这些封装好的结构或枚举变量中取出对应的配置字,最后写入寄存器中,完成对底层寄存器的配置. 可以看到,STM32的固件库函数对于程序开发人员来说是十分便利的存在,只需要填写言简意赅的参数就可以在完全不关心底层寄存器的前提下完成相关寄存器的配置,具有相当不错的通用性和易用性,也采取了一定措施保证库函数的安全性(主要引入了参数检查函数assert_param).但同时也应

STM32 可编程电压监测器(PVD)实现数据掉电保存

STM32内部有一个完整的上电复位和掉电复位电路,当供电电压达到2v时系统即能正常工作. STM32内部自带PVD功能,用于对MCU供电电压VDD进行监控.通过电源控制寄存器中的PLS[2:0]位可以用来设定监控电压的阀值,通过对外部电压进行比较来监控电源.当条件触发,需要系统进入特别保护状态,执行紧急关闭任务:对系统的一些数据保存起来,同时对外设进行相应的保护操作. 操作流程:     1).系统启动后启动PVD,并开启相应的中断.     PWR_PVDLevelConfig(PWR_PVD

修改STM32库函数中的晶振值

STM32F407的库文件中默认晶振值为25MHz,若外接晶振8MHz,则需修改以下几个地方: 1)修改HSE_VALUE的值 将#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ 修改为 #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ 2)修改PLL_M

STM32通过调用库函数进行编程

1.调用库函数编程和直接配置寄存器编程的区别: 2.CMSIS标准: 3.STM32库函数的组织: 4.程序例举: 调用库函数实现通过USART发送数据(26个大写的英文字母) 首先:在主函数部分先要(调用自己编写的函数)对USART要用到的I/O端口进行配置.打开系统时钟配置和对USART1进行参数配置 下图是通过调用库函数对USART1的参数进行配置,将其配置成异步收发模式.波特率用户可以自定的串口: /********************************************

STM32 HAL固件库编程的文件构架

对于我这种以前只接触过51和AVR单片机编程的小菜来说,现在开始学习STM32的编程,对于函数的功能以及C语言的语法都还好理解,难的是它提供的那一套硬件抽象层(HAL)驱动是怎么和其他的东东搭配在一起组成一个又一个的工程. 首先上两张从ST官方提供的HAL固件库文档截图 从这两张图的话,能对它的构架看出个一二,下面稍稍具体一点分析 HAL固件库编程,它的文件组织大致分三个部分 - HAL驱动 - CMSIS驱动 - 用户编写程序 而假如你使用的是ST官网的开发板,那么你还有一套现成的驱动可供使用

使用寄存器点亮LED——编程实战

stm32的编程和stc89c51还是存在着很多思想上的不同的,在51单片机中,我们点亮LED灯,只用给对应IO高低电平就可以了,而stm32中,就一个简单的GPIO,我们也需要配置好几个寄存器,而且,就算配置好GPIO寄存器,我们还必须有一步不能缺少的操作,那就是开启对应GPIO的时钟.在stm32的编程中,开启对应时钟是必不可少的一个操作,而且,开启时钟的操作必须在配置相应寄存器之前,以GPIO为例,如果我们先配置GPIO的寄存器,不开启时钟或者先配置GPIO寄存器,最后再开启时钟,都不能正