【SWM320】学习使用GPIO

依旧从点灯开始

先看原理图,C_ELC0和C_ELC1是连接在M2和B12,继电器是常开,1、2号脚就是低压侧,3、4号脚就是开关

继电器是一种低压控制高压的元器件。

低压侧,是一个电磁铁;高压侧,是一个开关,开关上面有弹簧,默认是断开的。

低压侧,电磁铁通电,就会吸引高压侧的永磁铁使开关闭合。

也就是当ELC_0为高电平时,螺旋管的电流导致磁铁通电使开关闭合;当ELC_0为低电平时,没有电流,电磁铁不通电

法一,可以更好了解寄存器

我现在要写实现引脚的函数,要知道引脚的地址,就得查数据手册

我需要B引脚组和M引脚组,我查

我写

cpp 复制代码
//GPIO寄存器基地址
#define Addr_GPIOB_Base    (0x40012000)
#define Addr_GPIOM_Base    (0x40015000)

//DATA寄存器
#define Offset_GPIO_DATA    (0X00)
#define Offset_GPIO_DIR        (0X04)

和B引脚组与M引脚组有关的我都先写上

cpp 复制代码
//PORT寄存器基地址
#define Addr_PORT_Base    (0x40010000)

先不管后面会不会用得着,我先写上

cpp 复制代码
//SEL寄存器
#define Offset_PORTB_SEL    (0X04)
#define Offset_PORTM_SEL0    (0X20)
#define Offset_PORTM_SEL1    (0X24)
cpp 复制代码
//MUX寄存器
#define Offset_PORTB_MUX0    (0X110)
#define Offset_PORTB_MUX1    (0X114)

#define Offset_PORTM_MUX0    (0X160)
#define Offset_PORTM_MUX1    (0X164)
#define Offset_PORTM_MUX2    (0X168)
#define Offset_PORTM_MUX3    (0X16C)
cpp 复制代码
//INEN寄存器
#define Offset_PORTB_INEN    (0X610)
#define Offset_PORTM_INEN    (0X640)

以上都是基地址和偏移量分开写,现在该加到一块了,直接得出引脚B组和引脚M组

cpp 复制代码
#define rPORTB_SEL     (*(volatile unsigned int*) (Addr_PORT_Base + Offset_PORTB_SEL) )

#define rPORTM_SEL0 (*(volatile unsigned int*) (Addr_PORT_Base + Offset_PORTM_SEL0) )
#define rPORTM_SEL1 (*(volatile unsigned int*) (Addr_PORT_Base + Offset_PORTM_SEL1) )

#define rGPIOB_DATA (*(volatile unsigned int*) (Addr_GPIOB_Base + Offset_GPIO_DATA) )
#define rGPIOB_DIR     (*(volatile unsigned int*) (Addr_GPIOB_Base + Offset_GPIO_DIR) )

#define rGPIOM_DATA (*(volatile unsigned int*) (Addr_GPIOM_Base + Offset_GPIO_DATA) )
#define rGPIOM_DIR     (*(volatile unsigned int*) (Addr_GPIOM_Base + Offset_GPIO_DIR) )

(*(volatile unsigned int*) (Addr_PORT_Base + Offset_PORTB_SEL))

^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

│ │ │

│ │ └─ 1. 计算地址

│ └─ 2. 强制类型转换

└─ 3. 解引用

有了这些宏之后,就可以编程初始化引脚为GPIO输出功能了:

我要写一个gpio_init_out函数,配置好PM2和PB12两个引脚

配置PB12:

rPORTB_SEL &= ~(3<<24);
配置PM2

rPORTM_SEL0 &= ~(3<<4);
设置引脚为输出(置1为输出)

rGPIOB_DIR |= (1<<12);

rGPIOM_DIR |= (1<<2 );
关闭输入使能

rPORTB_INEN &= ~(1<<12);

rPORTM_INEN &= ~(1<<2);
给PB12和PM2高电平(写1)

rGPIOB_DATA |= (1<<12); //GPIO B12输出高电平

rGPIOM_DATA |= (1<<2 ); //GPIO M2 输出高电平

此函数完整版:

cpp 复制代码
void gpio_init_out(void)
{
    //<1>将引脚的基本属性设置为GPIO:B12和M2    设置功能为00
    rPORTB_SEL &= ~(3<<24);

    rPORTM_SEL0 &= ~(3<<4);

    //<2>接通端口数据输出开关
    rGPIOB_DIR |=  (1<<12);

    rGPIOM_DIR |=  (1<<2 );

    //<3>关闭端口数据输入开关
    rPORTB_INEN &= ~(1<<12);

    rPORTM_INEN &= ~(1<<2);

    //<4>往端口引脚写数据,实现输出指定电平值
    rGPIOB_DATA |=  (1<<12);        //GPIO B12输出高电平
    rGPIOM_DATA |=  (1<<2 );        //GPIO M2 输出高电平

}

发现不起作用?我们用到了PORTB外设和PORTM外设,所有外设在使用前,都要先给外设提供时钟,修改gpio_init_out()函数,先使能外设时钟,再初始化

查系统时钟基地址和使能偏移量

cpp 复制代码
#define Addr_SYSCON_Base    0x40000000
#define Offset_SYS_CLKEN    (0x08)

#define rSYS_CLKEN     ( *(volatile unsigned int*)( Addr_SYSCON_Base + Offset_SYS_CLKEN ) )

使能B组和M组

cpp 复制代码
    //使能外设时钟 B M
    rSYS_CLKEN |= (1<<1);
    rSYS_CLKEN |= (1<<4);

所以,完整版应该是:

cpp 复制代码
#define Addr_SYSCON_Base    0x40000000
#define Offset_SYS_CLKEN    (0x08)

#define rSYS_CLKEN     ( *(volatile unsigned int*)( Addr_SYSCON_Base + Offset_SYS_CLKEN ) )

void gpio_init_out(void)
{
    //使能外设时钟 B M
    rSYS_CLKEN |= (1<<1);
    rSYS_CLKEN |= (1<<4);

    //<1>将引脚的基本属性设置为GPIO:B12和M2    设置功能为00
    rPORTB_SEL  &= ~(3<<24);
    rPORTM_SEL0 &= ~(3<<4);

    //<2>接通端口数据输出开关
    rGPIOB_DIR |=  (1<<12);

    rGPIOM_DIR |=  (1<<2 );

    //<3>关闭端口数据输入开关
    rPORTB_INEN &= ~(1<<12);

    rPORTM_INEN &= ~(1<<2);

    //<4>往端口引脚写数据,实现输出指定电平值    
    rGPIOB_DATA |=  (1<<12);        //GPIO B12输出高电平
    rGPIOM_DATA |=  (1<<2 );        //GPIO M2 输出高电平

}

也可以加上延时

cpp 复制代码
void delay_some_time(void)
{
    volatile uint32_t d= 0;
    d = 10000000;
    while(d--);
}

和led_ctrl函数

cpp 复制代码
void led_ctrl( int pwr )
{
    if( 0 == pwr )
    {
        rGPIOB_DATA &= ~(1<<12);    //B12输出低电平
        rGPIOM_DATA &= ~(1<<2 );    //M2 输出低电平
    }
    else
    {
        rGPIOB_DATA |= (1<<12);    //B12输出高电平
        rGPIOM_DATA |= (1<<2 );    //M2 输出高电平
    }

}

main函数就为

cpp 复制代码
int main(void)
{
    uint32_t chr;
    uint32_t err;
    SystemInit();
    SerialInit();

    printf("hello swm320\r\n");
    printf("cpu:%d\r\n",SystemCoreClock);

    //编程让某些引脚输出高电平    ELC0 M2        / ELC1 B12
    gpio_init_out( 0 );

    while(1==1)
    {
        led_ctrl( 1 );
        delay_some_time();
        led_ctrl( 0 );
        delay_some_time();

    }

}

法二,使用官方SDK编程

cpp 复制代码
void led_ctrl( int pwr )
{
    if( 0 == pwr )
    {
        GPIO_ClrBit(GPIOB, PIN12);    //设置输出0
        GPIO_ClrBit(GPIOM, PIN2 );    //设置输出0
    }
    else
    {
        GPIO_SetBit(GPIOB, PIN12);    //设置输出1
        GPIO_SetBit(GPIOM, PIN2 );    //设置输出1
    }
}

void delay_some_time(void)
{
    volatile uint32_t d= 0;
    d = 10000000;
    while(d--);

}

int main(void)
{    
    SystemInit();

    //初始化B12 M2为输出功能
    GPIO_Init(GPIOB, PIN12, 1, 0, 0);            //输出, 接LED
    GPIO_Init(GPIOM, PIN2 , 1, 0, 0);            //输出, 接LED

    while(1==1)
    {
        led_ctrl( 1 );
        delay_some_time();
        led_ctrl( 0 );
        delay_some_time();
    }
}
相关推荐
qq_284274052 小时前
机械原理笔记:平面机构自由度计算(复合铰链、局部自由度、虚约束)与四杆机构入门(含考点)
笔记·学习·平面·自动化·制造
qq_284274053 小时前
数控铣床与加工中心笔记:铣刀与刀柄系统、G54试切对刀、镜像加工指令、孔加工工艺(钻扩铰镗)与固定循环G73/G83/G81/G76/G87/G84
笔记·学习·自动化·制造
Titan20244 小时前
MySQL访问个人学习笔记
笔记·学习·mysql
小雪崩5 小时前
嵌入式学习 day64:字符设备驱动
学习
个 人 练 习 生5 小时前
C++ string 类模拟实现:从底层理解字符串(上)
开发语言·c++·经验分享·学习·程序人生
坤坤子吖5 小时前
C++智能指针:RAII、shared_ptr与内存泄漏
开发语言·c++·笔记·学习
词却7 小时前
OpenCV学习:MediaPipe 人脸网格检测
opencv·学习
李日华大战鸡红7 小时前
FOC SVPWM过调制(学习记录)
stm32·单片机·学习
AI职业加油站7 小时前
AI 校招现状:大模型应用工程师证书,助力简历能力证明
大数据·运维·人工智能·学习·职场发展
陈年老古董8 小时前
Hive 函数学习笔记(上):单行函数与炸裂函数
hive·笔记·学习