Freescale MC9S12G128 GPIO

MC9S12G-Family Block Diagram

在这里插入图片描述
不同芯片封装端口:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Port J相关寄存器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

The PIM includes these distinctive registers:
• Data registers and data direction registers for ports A, B, C, D, E, T, S, M, P, J and AD when used
as general-purpose I/O
• Control registers to enable/disable pull devices and select pullups/pulldowns on ports T, S, M, P, J
and AD on per-pin basis
• Single control register to enable/disable pull devices on ports A, B, C, D and E, on per-port basis
and on BKGD pin
• Control registers to enable/disable open-drain (wired-or) mode on ports S and M
• Interrupt flag register for pin interrupts on ports P, J and AD
• Control register to configure IRQ pin operation
• Routing register to support programmable signal redirection in 20 TSSOP only
• Routing register to support programmable signal redirection in 100 LQFP package only
• Package code register preset by factory related to package in use, writable once after reset. Also
includes bit to reprogram routing of API_EXTCLK in all packages.
• Control register for free-running clock outputs

寄存器简述

项目代码需要引入的头文件:
#include <hidef.h> /* common defines and macros /
#include “derivative.h” /
derivative-specific definitions */
mc9s12g128.h(寄存器相关定义)

  • PORTx (端口数据寄存器):可读写端口数据 1:高电平, 0:低电平;
  • DDRx(端口方向寄存器):设置端口方向 1:输出,0:输入;
  • PUCR(引脚上拉控制寄存器) 1:使能上拉,0:禁止上拉;
  • RDRIV(低功耗驱动寄存器) 1:低功耗 0:正常功耗;
  • x: 取值有A,B AB,C,D,CD,E等取值(不同版本芯片有差异,以实际芯片定义为准)

端口掩码定义,用于位操作,可查阅mc9s12g128.h文件中定义

端口操作

端口数据寄存器:PO
RTA,PORTB, PORTAB, PORTC, PORTD, PORTCD,PORTE
端口方向寄存器:DDRA,DDRB,DDRAB,DDRC,DDRD,DDRCD,DDRE
AB操作(PA0…PA7, PB0…PB7 共16个GPIO)

端口数据寄存器或端口方向寄存器每一位对应单个GPIO;

单个I/O操作

这个以PA端口举例:
PORTA
PORTA_PA0 ~ PORTA_PA7
PORTAB_PB
PORTAB_PA

设置单个GPIO的方向
DDRA
DDRA_DDRA0 ~ DDRA_DDRA7
DDRAB_DDRB
DDRAB_DDRA

端口J 相关寄存器:

/*** PTJ - Port J Data Register; 0x00000268 ***/
端口J 数据寄存器(0:低电平,1:高电平)
PTJ
PTJ_PTJ0 ~ PTJ_PTJ7
PTJ_PTJ0_MASK ~ PTJ_PTJ7_MASK

/*** PTIJ - Port J Input Register; 0x00000269 ***/
端口J 输入寄存器 (0:输入电平,1:输入高电平)
PTIJ
PTIJ_PTIJ0 ~ PTIJ_PTIJ7
PTIJ_PTIJ0_MASK ~ PTIJ_PTIJ7_MASK

/*** DDRJ - Port J Data Direction Register; 0x0000026A ***/
端口J 数据方向寄存器 (0:输入,1:输出)
DDRJ
DDRJ_DDRJ0 ~ DDRJ_DDRJ7
DDRJ_DDRJ0_MASK ~ DDRJ_DDRJ7_MASK

/*** PERJ - Port J Pull Device Enable Register; 0x0000026C ***/
端口J 拉设备使能寄存器
PERJ
PERJ_PERJ0 ~ PERJ_PERJ7
PERJ_PERJ0_MASK ~ PERJ_PERJ7_MASK

/*** PPSJ - Port J Polarity Select Register; 0x0000026D ***/
端口J 拉设备极性选择寄存器 (0:选择上拉,下降沿触发中断,1:选择下拉,上升沿触发中断)
PPSJ
PPSJ_PPSJ0 ~ PPSJ_PPSJ7
PPSJ_PPSJ0_MASK ~ PPSJ_PPSJ7_MASK

/*** PIEJ - Port J Interrupt Enable Register; 0x0000026E ***/
端口J 中断使能寄存器 (0:关闭中断, 1:使能中断)
PIEJ
PIEJ_PIEJ0 ~ PIEJ_PIEJ7
PIEJ_PIEJ0_MASK ~ PIEJ_PIEJ7_MASK

/*** PIFJ - Port J Interrupt Flag Register; 0x0000026F ***/
端口J 中断标志寄存器 (写1清中断,写0无效)
PIFJ
PIFJ_PIFJ0 ~ PIFJ_PIFJ1
PIFJ_PIFJ0_MASK ~ PIFJ_PIFJ7_MASK

其他端口都大同小异可以查阅相关文档;

GPIO点亮LED灯示例:

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */


#define LEDPORT     PORTA
#define LEDDIR      DDRA

#define LED1_PORT   PORTD_PD3
#define LED1_DIR    DDRD_DDRD3

/**
* @brief 延时函数
* @param none
* @return none
*/
void delay(void) {
    
    
  unsigned int i,j;
  for(i=0; i<2; i++) {
    
    
    for(j=0; j<50000; j++){
    
    
      ;
    }
  }
}

/**
* @brief LED GPIO初始化
* @param none
* @return none
*/
void LED_Init(void) {
    
    
  LEDDIR = 0xff;     // 设置PORTA(PA0~PA7 8PIN)端口为输出
  LEDPORT = 0x00;    // 设置PORTA默认电平全为0
  
  LED1_DIR = 0x1;      // 设置PORTD_PD3(PD3 PIN)GPIO为输出
  LED1_PORT = 0x0;     // 设置PORTD_PD3(PD3 PIN)GPIO低电平
}


void main(void) {
    
    
  /* put your own code here */
  
  DisableInterrupts;  // 关总中断
  LED_Init();
	EnableInterrupts;   // 开总中断


  for(;;) {
    
    
  
    // 操作整个端口 这里是PA端口(PA0~PA7)8个GPIO
    delay();
    LEDPORT = 0xf0;  // 端口操作
    LED1_PORT = 0;   // GPIO操作
    
    delay();
    LEDPORT = 0x0f;  // 端口操作
    LED1_PORT = 1;   // GPIO操作
    
    _FEED_COP(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

轮询方式GPIO按键示例:

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */

#define KEYCODE_0 (0)
#define KEYCODE_1 (1)
#define KEYCODE_2 (2)
#define KEYCODE_3 (3)
#define KEYCODE_NONE (0xff)

#define LED_PORT PORTA
#define LED_DIR  DDRA


#define KEY0_IN  PTIJ_PTIJ0
#define KEY1_IN  PTIJ_PTIJ1
#define KEY2_IN  PTIJ_PTIJ2
#define KEY3_IN  PTIJ_PTIJ3

#define KEY0_DIR DDRJ_DDRJ0
#define KEY1_DIR DDRJ_DDRJ1
#define KEY2_DIR DDRJ_DDRJ2
#define KEY3_DIR DDRJ_DDRJ3


unsigned char keycode = KEYCODE_NONE;

void key_delay(void){
    
    
  unsigned int i;
  i = 10000;
  while(i--){
    
    
    ;
  }
}


void led_gpio_init(void) {
    
    
  LED_DIR = 0xFF;
  LED_PORT = 0xFF;  
}

void key_gpio_init(void){
    
    
  // 设置GPIO输入模式 0:输入, 1:输出
  KEY0_DIR = 0;
  KEY1_DIR = 0;
  KEY2_DIR = 0;
  KEY3_DIR = 0;
}

/*
* @brief 查询方式检测按键
*
*
*/
void key_scaning(void) {
    
    
  // 有按键按下
  if ((KEY0_IN == 0) || (KEY1_IN == 0) || (KEY2_IN == 0) || (KEY3_IN == 0)) {
    
    
     // 按键去抖延时
     key_delay(); 

     // 确认有按键按下     
     if ((KEY0_IN == 0) || (KEY1_IN == 0) || (KEY2_IN == 0) || (KEY3_IN == 0)) {
    
    
        if (KEY0_IN == 0) {
    
    
           keycode = KEYCODE_0;
        } else if (KEY1_IN == 0) {
    
    
           keycode = KEYCODE_1;
        } else if (KEY2_IN == 0) {
    
    
           keycode = KEYCODE_2;
        } else if (KEY3_IN == 0) {
    
    
           keycode = KEYCODE_3;
        } else {
    
    
           keycode = KEYCODE_NONE;
        }
     }
  } else {
    
    
     keycode = KEYCODE_NONE;
  }
}


void key_process(void) {
    
    
  switch(keycode) {
    
    
    case KEYCODE_0:
      LED_PORT = ~(0x01 << 0); // LED0亮
      break;
    case KEYCODE_1:
      LED_PORT = ~(0x01 << 1); // LED1亮
      break;
    case KEYCODE_2:
      LED_PORT = ~(0x01 << 2); // LED2亮
      break;
    case KEYCODE_3:
      LED_PORT = ~(0x01 << 3); // LED3亮
      break;
    default:
      LED_PORT = 0xff;
      break;
  }

}


void main(void) {
    
    
  /* put your own code here */
  
  DisableInterrupts;
  led_gpio_init();
  key_gpio_init();
	EnableInterrupts;

 
  
  for(;;) {
    
    
    key_scaning();

    key_process();
    _FEED_COP(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

中断方式按键示例:

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */

#define KEYCODE_0 (0)
#define KEYCODE_1 (1)
#define KEYCODE_2 (2)
#define KEYCODE_3 (3)
#define KEYCODE_NONE (0xff)


#define LED PORTA
#define LED_dir DDRA

#define KEY0_IN   PTIJ_PTIJ0
#define KEY1_IN   PTIJ_PTIJ1
#define KEY2_IN   PTIJ_PTIJ2
#define KEY3_IN   PTIJ_PTIJ3

#define KEY0_dir  DDRJ_DDRJ0
#define KEY1_dir  DDRJ_DDRJ1
#define KEY2_dir  DDRJ_DDRJ2
#define KEY3_dir  DDRJ_DDRJ3


unsigned char keycode = KEYCODE_NONE;


void led_gpio_init(void) {
    
    
  LED_dir = 0xFF; // 设为输出模式, 1:输出 0:输入
  LED = 0xFF;     // LED全部熄灭高电平熄灭
}

void key_gpio_init(void) {
    
    
  KEY0_dir = 0;  // 设为输入模式, 1:输出 0:输入
  KEY1_dir = 0;  // 设为输入模式, 1:输出 0:输入
  KEY2_dir = 0;  // 设为输入模式, 1:输出 0:输入
  KEY3_dir = 0;  // 设为输入模式, 1:输出 0:输入
  
  PPSJ = 0x00;		      //极性选择寄存器,选择下降沿; 0:下降沿, 1:上升沿
  PIFJ = 0x0f;			    //对PIFJ的每一位写1来清除标志位;
  PIEJ = 0x0f;		      //中断使能寄存器;    0:关闭中断, 1:使能中断
  
}


void key_process(void) {
    
    
  switch(keycode) {
    
    
    case KEYCODE_0:
      LED = ~(0x01 << 0); // LED0亮
      break;
    case KEYCODE_1:
      LED = ~(0x01 << 1); // LED1亮
      break;
    case KEYCODE_2:
      LED = ~(0x01 << 2); // LED2亮
      break;
    case KEYCODE_3:
      LED = ~(0x01 << 3); // LED3亮
      break;
    default:
      LED = 0xff;
      break;
  }

}

/*
* @brief 按键中断函数
*/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt VectorNumber_Vportj void PTJ_IRQ(void) {
    
    
  // 判断中断标志
  if (PIFJ != 0) {
    
    
    PIFJ = 0xff; // 清除中断标志
    
    if (KEY0_IN == 0) {
    
    
        keycode =  KEYCODE_0;
    } else if (KEY1_IN == 0) {
    
    
        keycode =  KEYCODE_1;
    } else if (KEY2_IN == 0) {
    
    
        keycode =  KEYCODE_2;    
    } else if (KEY3_IN == 0) {
    
    
        keycode =  KEYCODE_3;    
    } else {
    
    
        //keycode = KEYCODE_NONE;
    }
  }
  
}
#pragma CODE_SEG DEFAULT


void main(void) {
    
    
  /* put your own code here */
  
  DisableInterrupts;
  led_gpio_init();
  key_gpio_init();
	EnableInterrupts;


  for(;;) {
    
    
  
  key_process();
    _FEED_COP(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

注意 ,中断服务程序的写法:
写法1,中断函数指明中断向量号:
main.c
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt 中断向量号 void 中断服务函数名(void) {
// 中断服务程序代码段
}
#pragma CODE_SEG DEFAULT
中断向量号在mc9s12g128.h文件里有定义,如:
/**************** interrupt vector numbers ****************/
#define VectorNumber_Vportj 24U

写法2,修改prm文件,在Project.prm文件声明中断函数:
main.c:
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void 中断服务函数名(void) {
// 中断服务程序代码段
}
#pragma CODE_SEG DEFAULT

Project.prm:
文件尾增加 VECTOR ADDRESS 中断向量 中断服务函数名
例如:ProtJ 中断向量:0xFFCE ,中断函数名:PTJ_IRQ
VECTOR ADDRESS 0xFFCE PTJ_IRQ

中断向量在mc9s12g128.h文件里有定义,如:
/**************** interrupt vector table ****************/
#define Vportj 0xFFCEU

猜你喜欢

转载自blog.csdn.net/u013420428/article/details/112825586