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