本文是继MBED串口API移植的又一篇系列文章,前阵子忙着赶项目,移植完了却没来得及写成文章来分享,今天来补上,一来可以温故知新,二来也可以献出自己的一点微薄之力。写的不好,移植的也不一定好,请大家多多指教。本文的gpio_api模块与mbed官方的会有一些不同,原因是加入了我个人理解的一些东西。
一、关联文件
1、ierror.h
/*
**************************************************************
file: ierror.c
date: 2016-8-15
ver : 1.00.00
**************************************************************
*/
#include
#include
#include "device.h"
#include "toolchain.h"
#include "ierror.h"
#if DEVICE_STDIO_MESSAGES
#include
#endif
WEAK void error(const char* format, ...) {
#if DEVICE_STDIO_MESSAGES
va_list arg;
va_start(arg, format);
vfprintf(stderr, format, arg); /* 打印到屏幕输出 */
va_end(arg);
#endif
exit(1);
}
2、ierror.c
/*
**************************************************************
file: ierror.c
date: 2016-8-15
ver : 1.00.00
**************************************************************
*/
#include
#include
#include "device.h"
#include "toolchain.h"
#include "ierror.h"
#if DEVICE_STDIO_MESSAGES
#include
#endif
WEAK void error(const char* format, ...) {
#if DEVICE_STDIO_MESSAGES
va_list arg;
va_start(arg, format);
vfprintf(stderr, format, arg); /* 打印到屏幕输出 */
va_end(arg);
#endif
exit(1);
}
3、iassert.h
/*
**************************************************************
file: iassert.h
date: 2016-8-15
ver : 1.00.00
**************************************************************
*/
#ifndef _I_ASSERT_H
#define _I_ASSERT_H
void iassert_internal(const char *expr, const char *file, int line);
#ifdef I_NDEBUG
#define I_ASSERT(expr) ((void)0)
#else
#define I_ASSERT(expr) \
do { \
if (!(expr)) { \
iassert_internal(#expr, __FILE__, __LINE__); \
} \
} while (0)
#endif
#endif
4、iassert.c
/*
*/
#include "iassert.h"
#include "ierror.h"
void iassert_internal(const char *expr, const char *file, int line)
{
error("mbed assertation failed: %s, file: %s, line %d \n", expr, file, line);
}
5、portnames.h
/*
*******************************************************************************
*******************************************************************************
*/
#ifndef _PORT_NAMES_H
#define _PORT_NAMES_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PORTA = 0,
PORTB = 1,
PORTC = 2,
PORTD = 3,
PORTE = 4,
PORTF = 5,
PORTG = 6,
PORTH = 7
} PORTNAME;
#ifdef __cplusplus
}
#endif
#endif
6、stm32f1xx.h
二、gpio_api.h
/**
******************************************************************************
* File Name : gpio_api.h
* Description :
******************************************************************************
*/
#include "pinnames.h"
/* extern prototype *************************/
void gpio_init(uint32_t pin); /* 初始化引脚,使能引脚时钟 */
void gpio_format(uint32_t pin,uint32_t mode,uint32_t pupd);
void gpio_dir(uint32_t pin,PIN_DIRECTION dir);
void gpio_mode(uint32_t pin,uint32_t mode);
void find_port(uint32_t pin,GPIO_TypeDef **port);
void gpio_write(uint32_t pin,uint32_t value);
uint32_t gpio_read(uint32_t pin);
/* gpio in ***********************************/
void gpio_init_in(uint32_t pin); /* 初始化引脚为输入模式 */
void gpio_init_in_ex(uint32_t pin,uint32_t value);
/* gpio out **********************************/
void gpio_init_out(uint32_t pin); /* 初始化引脚为输出模式 */
void gpio_init_out_ex(uint32_t pin,uint32_t value);
三、gpio_api.c
/**
******************************************************************************
* File Name : gpio_api.c
* Description :
******************************************************************************
*/
#include "iassert.h"
#include "ierror.h"
#include "stm32f1xx.h"
#include "gpio_api.h"
#include "portnames.h"
/* private prototype *****************************************/
static void _gpio_init_out(uint32_t pin,uint32_t pin_mode,uint32_t value);
static void _gpio_init_in(uint32_t pin,uint32_t mode);
/* genrate api **********************************************************/
/**
* 描述:初始化GPIO引脚,使能GPIO时钟
* pin :引脚名称,必须为 PIN_NAME 枚举中的一个
*/
void gpio_init(uint32_t pin)
{
if(pin == (uint32_t)NC)
return;
uint32_t port = STM_PORT(pin);
switch(port)
{
case PORTA:
__HAL_RCC_GPIOA_CLK_ENABLE();
break;
case PORTB:
__HAL_RCC_GPIOB_CLK_ENABLE();
break;
case PORTC:
__HAL_RCC_GPIOC_CLK_ENABLE();
break;
case PORTD:
__HAL_RCC_GPIOD_CLK_ENABLE();
break;
case PORTE:
__HAL_RCC_GPIOE_CLK_ENABLE();
break;
default:
error("Pinmap error: wrong port number.");
break;
}
}
/**
* 描述: 按指定参数格式化引脚
* pin : 引脚名称,必须为 PIN_NAME 枚举中的一个
* mode: 与HAL库中的gpio_mode一致
* pupd: 与HAL库一致
*/
void gpio_format(uint32_t pin,uint32_t mode,uint32_t pupd)
{
I_ASSERT(pin != NC);
GPIO_InitTypeDef gpio_initstruct;
GPIO_TypeDef *port = NULL;
uint32_t gpio_pin = 1<
BSRR = gpio_pin;
}else{
port->BSRR = (uint32_t)gpio_pin<<16;
}
}
uint32_t gpio_read(uint32_t pin)
{
I_ASSERT(pin != NC);
uint32_t pinbit;
GPIO_TypeDef *port = NULL;
uint32_t pin_idx = STM_PIN(pin);
uint32_t gpio_pin = 1<
IDR & gpio_pin) != (uint32_t)0){
pinbit = 1;
}else{
pinbit = 0;
}
return pinbit;
}
/* digital in ***********************************************************/
void gpio_init_in(uint32_t pin)
{
gpio_init_in_ex(pin,GPIO_MODE_INPUT);
}
void gpio_init_in_ex(uint32_t pin,uint32_t mode)
{
_gpio_init_in(pin,mode);
}
static void _gpio_init_in(uint32_t pin,uint32_t mode)
{
gpio_init(pin);
if(pin != NC){
gpio_dir(pin,PIN_INPUT);
gpio_mode(pin,mode);
}
}
/* digital out *********************************************************/
void gpio_init_out(uint32_t pin)
{
gpio_init_out_ex(pin,0); /* 默认输出低电平 */
}
/**
* value -- value = 0(level low) or 1(level high)
*/
void gpio_init_out_ex(uint32_t pin,uint32_t value)
{
_gpio_init_out(pin,GPIO_MODE_OUTPUT_PP,value);
}
/**
* value -- value = 0(level low) or 1(level high)
*/
static void _gpio_init_out(uint32_t pin,uint32_t pin_mode,uint32_t value)
{
gpio_init(pin);
if(pin != NC){
gpio_write(pin,value);
gpio_dir(pin,PIN_OUTPUT);
gpio_mode(pin,pin_mode);
}
}
四、使用举例
例如:把 PA_14脚配置为输出模式,初始为高电平;把PA_15配置成输入;
#include "gpio_api.h"
void main(void)
{
gpio_init_out(PA_14);/* 按缺省参数初始化引脚 */
gpio_write(PA_14,1);/* 初始化为高电平 */
uint8_t pin_value = gpio_read(PA_14);/* 读引脚状态 */
gpio_init_in(PA_15);
for(;;)
{
}
}