K60学习笔记三:GPIO口的底层驱动操作带API接口

GPIO 用于普通I/O口的输入输出
C预备知识:
const 修饰只读常量
volatile修饰易变量,表示编译器不能进行优化
GPIO模块的编程步骤:
1.设置PORT端口为GPIO复用
2.设置GPIO口的输入输出方向

在进行库开发时要有软件分层的思想 。

GPIO.c

GPIO_MemMapPtr GPIOX[PTX_MAX] = {PTA_BASE_PTR,PTB_BASE_PTR,PTC_BASE_PTR, PTD_BASE_PTR, PTE_BASE_PTR}; //定义五个指针数组保存 GPIOX 的地址
//这些数组元素表达了GPIO_MemMapPtr结构体指针的地址
//GPIO初始化
void gpio_init (PTXn_e ptxn, GPIO_CFG cfg, uint8 data)
{


    //端口方向控制输入还是输出
    if(  cfg == GPI )
    //在GPIO.h中有枚举:
    //typedef enum GPIO_CFG
// {
// //这里的值不能改!!!
// GPI = 0, //定义管脚输入方向 
// GPO = 1, //定义管脚输出方向
// } GPIO_CFG;

    {
        //设置端口方向为输入
        GPIO_PDDR_REG(GPIOX_BASE(ptxn)) &= ~(1 << PTn(ptxn));       // GPIO PDDR 管脚号 清0,即对应管脚配置为端口方向输入
       //#define GPIOX_BASE(PTxn) GPIOX[PTX(PTxn)] //GPIO模块的地址
    }
    else
    {
        //设置端口方向为输出
        GPIO_PDDR_REG(GPIOX_BASE(ptxn)) |= (1 << PTn(ptxn));        // GPIO PDDR 管脚号 置1,即对应管脚配置为端口方向输出

        //端口输出数据
        if(data == 0)
        {
            GPIO_PDOR_REG(GPIOX_BASE(ptxn)) &= ~(1 << PTn(ptxn));   // GPIO PDOR 管脚号 清0,即对应管脚配置为端口输出低电平
        }
        else
        {
            GPIO_PDOR_REG(GPIOX_BASE(ptxn))  |= (1 << PTn(ptxn));   // GPIO PDOR 管脚号 置1,即对应管脚配置为端口输出高电平
        }
    }

    //复用管脚为GPIO功能
    port_init( ptxn, ALT1);
}

//这个GPIO口的操作和PORT端口定义的操作差不多

/*! *  @brief 设置引脚数据方向 *  @param PTxn 端口 *  @param cfg 引脚方向,0=输入,1=输出 *  @since v5.0 * Sample usage: gpio_ddr (PTA8, GPI); //设置 PTA8 管脚为输入 */
void    gpio_ddr   (PTXn_e ptxn, GPIO_CFG cfg)
{
    //端口方向控制输入还是输出
    if(  cfg == GPI )
    {
        //设置端口方向为输入
        GPIO_PDDR_REG(GPIOX_BASE(ptxn)) &= ~(1 << PTn(ptxn));           // GPIO PDDR 管脚号 清0,即对应管脚配置为端口方向输入
    }
    else
    {
        //设置端口方向为输出
        GPIO_PDDR_REG(GPIOX_BASE(ptxn)) |= (1 << PTn(ptxn));            // GPIO PDDR 管脚号 置1,即对应管脚配置为端口方向输出
    }
}

/*! *  @brief 设置引脚状态 *  @param PTxn 端口 *  @param data 输出初始状态,0=低电平,1=高电平 (对输入无效) *  @since v5.0 *  @warning 务必保证数据方向为输出(DEBUG模式下,有断言进行检测) * Sample usage: gpio_set (PTA8, 1); // PTA8 管脚 输出 1 */
void gpio_set (PTXn_e ptxn, uint8 data)
{
    ASSERT( BIT_GET( GPIO_PDDR_REG(GPIOX_BASE(ptxn)) , PTn(ptxn)) == GPO ); // 断言,检测 输出方向是否为输出
                                                                            // 获取 GPIO PDDR 管脚号 ,比较是否为输出

    //端口输出数据
    if(data == 0)
    {
        GPIO_PDOR_REG(GPIOX_BASE(ptxn)) &= ~(1 << PTn(ptxn));   // GPIO PDOR 管脚号 清0,即对应管脚配置为端口输出低电平
    }
    else
    {
        GPIO_PDOR_REG(GPIOX_BASE(ptxn))  |= (1 << PTn(ptxn));   // GPIO PDOR 管脚号 置1,即对应管脚配置为端口输出高电平
    }
}


/*! *  @brief 反转引脚状态 *  @param PTxn 端口 *  @since v5.0 *  @warning 务必保证数据方向为输出(DEBUG模式下,有断言进行检测) * Sample usage: gpio_turn (PTA8); // PTA8 管脚 输出 反转 */
void gpio_turn (PTXn_e ptxn)
{
    ASSERT( BIT_GET( GPIO_PDDR_REG(GPIOX_BASE(ptxn)) , PTn(ptxn)) == GPO ); // 断言,检测 输出方向是否为输出
                                                                            // 获取 GPIO PDDR 管脚号 ,比较是否为输出

    GPIO_PTOR_REG( GPIOX_BASE(ptxn))  =  1 << (PTn(ptxn ));                 // GPIO PTOR ptxn 置1,其他清0 ,即对应管脚配置为端口输出反转,其他位不变
                                                                            // 此处不能用 BIT_SET 这个宏来置1 ,因为必须保证其他位 不变,其他位直接清0即可
}

/*! *  @brief 读取引脚输入状态 *  @param PTxn 端口 *  @return 管脚的状态,1为高电平,0为低电平 *  @since v5.0 *  @warning 务必保证数据方向为输入(DEBUG模式下,有断言进行检测) * Sample usage: uint8 pta8_data = gpio_get (PTA8); // 获取 PTA8 管脚 输入电平 */
uint8 gpio_get(PTXn_e ptxn)
{
    ASSERT( BIT_GET( GPIO_PDDR_REG(GPIOX_BASE(ptxn)) , PTn(ptxn)) == GPI ); // 断言,检测 输出方向是否为输入
                                                                            // 获取 GPIO PDDR 管脚号 ,比较是否为输入

    return ((GPIO_PDIR_REG(GPIOX_BASE(ptxn)) >> PTn(ptxn )) & 0x01);        // 获取 GPIO PDIR ptxn 状态,即读取管脚输入电平
}

//GPIO口的一些操作和PORT端口的定义是一样的
//要注意合理的使用断言
//在这里用断言来判断引脚的数据输入还是输出
//#BIT_GET( GPIO_PDDR_REG(GPIOX_BASE(ptxn)) , PTn(ptxn) (((var)>>(n))&0x01) //读取变量var 的n位(即第//n+1位)

在这个库文件中有一个介于底层驱动和用户程序调用之间还有一层程序调用,使用户有更好的API接口

LED.H
#ifndef _LED_H_
#define _LED_H_
//枚举LED端口
typeof enum {
    LED0,
    LED1,
    LED3,
    LEDMAX,
}LED_e;
//枚举LED亮灭状态
typeof enum{
    LED_ON,
    LED_OFF,
}LED_state;

//声明API接口
extern void  led_init(LED_e); //初始化LED
extern void  led(LED_e,LED_state);//设置LED状态
extern void  led_turn(LED_e); //翻转LED状态

#endif
LED.C

//包含头文件
//定义LED编号对应的管脚
PTXn_e LED_PTXn[LED_MAX] = {PTD4,PTD5,PTD6,PTD7};

//初始化LED
void led_init(LED_e ledn)
{
    if(ledn < LED_MAX)
    {
        gpio_init(LED_PTxn[ledn],GPO,LED_OFF);
    } //当ledn< LED_MAX时,只初始化这一个
    else
    {
        ledn = LED_MAX;
        while(ledn--)
            gpio_init(LED_PTxn[ledn],GPO,LED_OFF);
    }//当ledn >= LED_MAX时,全部初始化
}

//设置LED亮灭
void led(LED_e ledn ,LED_status status)
{
    if(ledn < LED_MAX)
    {
        ggpio_set(LED_PTxn[ledn],status);
    } //当ledn< LED_MAX时,只初始化这一个
    else
    {
        ledn = LED_MAX;
        while(ledn--)
            gpio_set(LED_PTxn[ledn],status);
    }//当ledn >= LED_MAX时,全部初始化
}

//翻转LED状态
void led_turn (LED_e ledn)
{
    if(ledn < LED_MAX)
    {
        gpio_turn(LED_PTxn[ledn]);
    } //当ledn< LED_MAX时,只初始化这一个
    else
    {
        ledn = LED_MAX;
        while(ledn--)
            gpio_turn(LED_PTxn[ledn]);
    }//当ledn >= LED_MAX时,全部初始化
}


//在这些函数都很简单,就是同样的条件结构。

你可能感兴趣的:(编程)