zoukankan      html  css  js  c++  java
  • 东芝MCU实现位带操作

    位带操作简介

    位带操作的概念其实30年前就有了,那还是 8051单片机开创的先河,如今ARM CM3 将此能力进化,可以说,这里的位带操作是8051 位寻址区的威力大幅加强版。即如果要改写某个寄存器的某一位,通过改写这一位映射的地址即可。东芝的TT_M3HQ开发板也是ARM CM3的MCU,实现了位带操作,就可以如同51单片机控制GPIO口一样的方便。

    位带操作的优越性

    初学51时,对某一个IO口进行输出操作,或者读取输入时,可以通过如下方式:

    #define LED P1^0
    #define KEY P1^2
    
    LED = 0;		//输出0
    
    if(KEY == 0)		//读取按键输入
    {
    
    }
    

    对于东芝TMPM3HQFDFG,如果没有位带操作,我们需要使用如下函数来实现读取和输入。在txz_gpio.c和txz_gpio.h两个库文件中,我们可以了解到写函数和读函数的使用方法。

    写函数:

    gpio_t port;
    
    //PK4输出低电平
    gpio_write_bit(&port, GPIO_PORT_K, GPIO_PORT_4, GPIO_Mode_DATA, GPIO_PIN_RESET);
    
    //PK4输出高电平
    gpio_write_bit(&port, GPIO_PORT_K, GPIO_PORT_4, GPIO_Mode_DATA, GPIO_PIN_SET);
    

    读函数:

    //读取PV3输入
    
    gpio_pinstate_t key_status;
    gpio_t port;
    gpio_read_bit(&port, KEY_PORT, KEY_PIN, GPIO_Mode_DATA, &key_status);
    

    而如果实现了位带操作,我们只需要使用两个宏就可以实现:

    PK4输出:PKout(4) = 0;
    读取PV3输入:in = PVin(3);
    

    实现按键按下LED闪烁:

       if(PVin(3) == GPIO_PIN_RESET)	//按键按下LED闪烁
        {
            PKout(4) = 1;   //点亮 
            delay_ms(50);
    
            PKout(4) = 0;   //熄灭
            delay_ms(50);
        }
    

    是不是很简单呢?通过查看官方txz_gpio.c库文件中输出和输入函数的实现,可以看出是使用的位带方式,但是看着不是很简洁,有没有更简单一些的实现方法呢?

    位带操作的实现

    新建sys.h,主要通过宏定义的方式实现IO的输出和输入。

    #ifndef  __SYS_H__
    #define __SYS_H__
    
    #include "TMPM3HQ.h"
    #include "TMPM3Hy.h"
    
    #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
    #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
    #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
    
    #define PORTx_BASE(group)       (0x400C0000UL + (uint32_t)((0x0000100UL) * (group)))
    #define PORTx_MODE_BASE(group)   ((uint32_t)(PORTx_BASE(group)) + (uint32_t)(GPIO_Mode_DATA))
    
    #define PORTA_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_A)
    #define PORTB_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_B)
    #define PORTC_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_C)
    #define PORTD_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_D)
    #define PORTE_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_E)
    #define PORTF_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_F)
    #define PORTG_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_G)
    #define PORTH_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_H)
    #define PORTJ_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_J)
    #define PORTK_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_K)
    #define PORTL_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_L)
    #define PORTM_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_M)
    #define PORTN_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_N)
    #define PORTP_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_P)
    #define PORTR_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_R)
    #define PORTT_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_T)
    #define PORTU_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_U)
    #define PORTV_ODR_ADDR      PORTx_MODE_BASE(GPIO_PORT_V)
    
    #define PAout(n)   BIT_ADDR(PORTA_ODR_ADDR, n)   
    #define PBout(n)   BIT_ADDR(PORTB_ODR_ADDR, n)   
    #define PCout(n)   BIT_ADDR(PORTC_ODR_ADDR, n)   
    #define PDout(n)   BIT_ADDR(PORTD_ODR_ADDR, n)   
    #define PEout(n)   BIT_ADDR(PORTE_ODR_ADDR, n)   
    #define PFout(n)   BIT_ADDR(PORTF_ODR_ADDR, n)   
    #define PGout(n)   BIT_ADDR(PORTG_ODR_ADDR, n)   
    #define PHout(n)   BIT_ADDR(PORTH_ODR_ADDR, n)   
    #define PJout(n)   BIT_ADDR(PORTJ_ODR_ADDR, n)   
    #define PKout(n)   BIT_ADDR(PORTK_ODR_ADDR, n)   
    #define PLout(n)   BIT_ADDR(PORTL_ODR_ADDR, n)   
    #define PMout(n)   BIT_ADDR(PORTM_ODR_ADDR, n)   
    #define PNout(n)   BIT_ADDR(PORTN_ODR_ADDR, n)   
    #define PPout(n)   BIT_ADDR(PORTP_ODR_ADDR, n)   
    #define PRout(n)   BIT_ADDR(PORTR_ODR_ADDR, n)   
    #define PTout(n)   BIT_ADDR(PORTT_ODR_ADDR, n)   
    #define PUout(n)   BIT_ADDR(PORTU_ODR_ADDR, n)   
    #define PVout(n)   BIT_ADDR(PORTV_ODR_ADDR, n)   
    
    
    //实现指定管脚置位和复位
    /*
    PORTx_SET(GPIO_PORT_K, 5);
    PORTx_CLR(GPIO_PORT_K, 4);
    */
    #define PORTx_SET(group, pin)   (*((__IO uint32_t *)PORTx_MODE_BASE(group)) |= (uint32_t)(0x0000001UL<< pin))
    #define PORTx_CLR(group, pin)   (*((__IO uint32_t *)PORTx_MODE_BASE(group)) &= ~((uint32_t)(0x0000001UL<< pin)))
    
    /*
    //实现指定管脚置位和复位
    #define PORTx_SET(group, pin)   (BIT_ADDR(PORTx_MODE_BASE(group), pin)=1)
    #define PORTx_CLR(group, pin)   (BIT_ADDR(PORTx_MODE_BASE(group), pin)=0)
    */
    
    //读取指定引脚的输入状态
    #define READ_PIN(group, pin)    ((*((__IO uint32_t *)(PORTx_MODE_BASE(group))) & (uint32_t)(0x0000001UL<< pin)) >> pin)
    
    //输入状态 = GPIO_PIN_RESET or GPIO_PIN_SET
    #define PAin(pin)   READ_PIN(GPIO_PORT_A, pin)
    #define PBin(pin)   READ_PIN(GPIO_PORT_B, pin)
    #define PCin(pin)   READ_PIN(GPIO_PORT_C, pin)
    #define PDin(pin)   READ_PIN(GPIO_PORT_D, pin)
    #define PEin(pin)   READ_PIN(GPIO_PORT_E, pin)
    #define PFin(pin)   READ_PIN(GPIO_PORT_F, pin)
    #define PGin(pin)   READ_PIN(GPIO_PORT_G, pin)
    #define PHin(pin)   READ_PIN(GPIO_PORT_H, pin)
    #define PJin(pin)   READ_PIN(GPIO_PORT_J, pin)
    #define PKin(pin)   READ_PIN(GPIO_PORT_K, pin)
    #define PLin(pin)   READ_PIN(GPIO_PORT_L, pin)
    #define PMin(pin)   READ_PIN(GPIO_PORT_M, pin)
    #define PNin(pin)   READ_PIN(GPIO_PORT_N, pin)
    #define PPin(pin)   READ_PIN(GPIO_PORT_P, pin)
    #define PRin(pin)   READ_PIN(GPIO_PORT_R, pin)
    #define PTin(pin)   READ_PIN(GPIO_PORT_T, pin)
    #define PUin(pin)   READ_PIN(GPIO_PORT_U, pin)
    
    #define PVin(pin)   READ_PIN(GPIO_PORT_V, pin)
    
    
    #endif
    

    实际应用

    LED初始化为普通输出:

    #define LED_ON 	PKout(4)=1
    #define LED_OFF 	PKout(4)=0
    
    void LED_Init(void)
    {
        gpio_t port;
        port.p_pk_instance = TSB_PK;    //GPIOK
        
        gpio_init(&port, GPIO_PORT_K);    //初始化GPIOK 
        gpio_func(&port, GPIO_PORT_K, GPIO_PORT_4, GPIO_PK4_OUTPUT, GPIO_PIN_OUTPUT);
        //初始化熄灭
        gpio_write_bit(&port, GPIO_PORT_K, GPIO_PORT_4, GPIO_Mode_DATA, GPIO_PIN_RESET);
           //LED_OFF;	//位带操作方式
    }
    

    KEY初始化为上拉输入:

    #define KEY_IN 	PVin(3)
    
    void KEY_Init(void)
    {
        gpio_t port;
    
        port.p_pv_instance = TSB_PV;    
        
        gpio_init(&port, GPIO_PORT_V);    
    
        gpio_func(&port, GPIO_PORT_V, GPIO_PORT_3, GPIO_PV3_INPUT, GPIO_PIN_INPUT);   //输入模式
        gpio_SetPullUp(&port, GPIO_PORT_V, GPIO_PORT_3, GPIO_PIN_SET);        //上拉
    }
    

    main.c主函数实现按键按下LED闪烁:

    #include "main.h"
    
    int main(void)
    {
        LED_Init();
        delay_init();
        KEY_Init();
        
        while(1)
        {
            if(KEY_IN == GPIO_PIN_RESET)
            {
    	     LED_ON;
                delay_ms(50);
    	     LED_OFF;
                delay_ms(50);
            }
        }
    }
    

    总结

    有了上面的代码,我们就可以像 51/AVR 一样操作东芝TT_M3HQ开发板的 IO 口了。


    推荐阅读


    • 我的个人博客:www.wangchaochao.top
    • 我的公众号:mcu149

  • 相关阅读:
    数据绑定表达式语法(Eval,Bind区别)
    使用博客园的第一件事 自定义主题
    sql2000 跨服务器复制表数据
    使用UpdatePanel 局部刷新出现中文乱码的解决方法!!
    MMC不能打开文件MSC文件
    sql 日期 、时间相关
    loaded AS2 swf call function in AS3 holder
    Rewrite the master page form action attribute in asp.net 2.0
    100万个不重复的8位的随机数
    flash 中实现斜切变型
  • 原文地址:https://www.cnblogs.com/whik/p/11488709.html
Copyright © 2011-2022 走看看