【CH559单片机 】GPIO输出模式以及外部中断介绍以及示例
- 📌E8051 USB系列中的CH559单片机.
- 📍本示例基于官方所提供的的参考示例资料:
https://www.wch.cn/products/CH549.html

🌻GPIO 简介
- 🌿CH559 提供最多 45 个 I/O 引脚,部分引脚具有复用功能。其中,端口 P0~P3 的输入和输出以及 P4 的输出都可以按位寻址。
- 🌿如果引脚没有被配置成复用功能,则默认是通用 I/O 引脚状态。作为通用数字 I/O 使用时,所有 I/O 端口都具有真正的“读–修改–写”功能,支持 SETB 或者 CLR 等位操作指令独立地改变某些引脚的方向或者端口电平等。


📑端口配置寄存器(PORT_CFG):

📑Pn 端口输入输出寄存器(Pn):

📑Pn 端口方向控制寄存器(Pn_DIR):

📑P0 端口上拉使能寄存器(P0_PU)和 Pn 端口上拉使能寄存器(Pn_PU),此处 n=1/2/3:

🧾由 PORT_CFG 中的位 bPn_OC 和端口方向控制寄存器 Pn_DIR 以及端口上拉使能寄存器 Pn_PU 组合
实现 Pn 端口的相关配置,具体如下。

🎯GPIO总结的配置寄存器表

⛳CH559中断向量表


📝中断相关寄存器列表
✒中断使能寄存器(IE)

🧧扩展中断使能寄存器(IE_EX):

📗GPIO 中断使能寄存器(GPIO_IE):


⏳中断优先级控制寄存器(IP):

⌚扩展中断优先级控制寄存器(IP_EX):


📢在CH559单片机中数据类型注意事项
- 定义的返回值数据类型为UINT8的函数不能用UINT8类型的变量来接收。
👉这个坑,需要注意,写着是8位增强型单片机,但是实际上运行是以16位的数据总线宽度。
- 👉例如端口0、1、2、3引脚模式设置
UINT8 CH559GPIOModeSelt(UINT8 Port,UINT8 Mode,UINT8 PinNum)
{
UINT8 Pn_DIR,Pn_PU;
if(Port >= 4){
return 0;
}
switch (Mode){
case 0: //仅输入,无上拉
PORT_CFG &= ~(bP0_OC << Port);//11111101
Pn_DIR &= ~(1<<PinNum);
Pn_PU &= ~(1<<PinNum);
break;
case 1: //仅输入,带上拉
PORT_CFG &= ~(bP0_OC << Port);
Pn_DIR &= ~(1<<PinNum);
Pn_PU |= 1<<PinNum;
break;
case 2: //推挽输出,高低电平强驱动
PORT_CFG &= ~(bP0_OC << Port);
Pn_DIR |= (1<<PinNum);
break;
case 3: //开漏输出,无上拉,支持输入
PORT_CFG |= (bP0_OC << Port);
Pn_DIR &= ~(1<<PinNum);
Pn_PU &= ~(1<<PinNum);
break;
case 4: //开漏输出,无上拉,当转变输出由低到高时,仅驱动2个时钟的高电平
PORT_CFG |= (bP0_OC << Port);
Pn_DIR |= 1<<PinNum;
Pn_PU &= ~(1<<PinNum);
break;
case 5: //弱准双向(标准51模式),开漏输出,带上拉
PORT_CFG |= (bP0_OC << Port);
Pn_DIR &= ~(1<<PinNum);
Pn_PU |= 1<<PinNum;
break;
case 6: //准双向(标准51模式),开漏输出,带上拉,当转变输出由低到高时,仅驱动2个时钟的高电平
PORT_CFG |= (bP0_OC << Port);
Pn_DIR |= 1<<PinNum;
Pn_PU |= 1<<PinNum;
break;
default:
break;
}
if(Port == 0){
P0_DIR = Pn_DIR;
P0_PU = Pn_PU;
}
if(Port == 1){
P1_DIR = Pn_DIR;
P1_PU = Pn_PU;
}
if(Port == 2){
P2_DIR = Pn_DIR;
P2_PU = Pn_PU;
}
if(Port == 3){
P3_DIR = Pn_DIR;
P3_PU = Pn_PU;
}
return 1;
}
- 需要定义一个
UINT16的变量来接收UINT8函数返回值。
UINT16 value==CH559GPIOModeSelt(2,2,4);//P2端口,推挽模式,P2.4
📝GPIO输出以及GPIO中断示例代码
代码中P14为gpio中断引脚,触发方式:低电平触发,P12和P24设置为了推挽输出模式,
/********************************** (C) COPYRIGHT *******************************
* File Name : GPIO.C
* Author : WCH
* Version : V1.9
* Date : 2021/12/15
* Description : CH559的GPIO操作,使用时可以简单操作,直接配置
IO配置主要跟一下寄存器的状态有关系
bPn_OC & Pn_DIR & Pn_PU: pin input & output configuration for Pn (n=0/1/2/3)
详细介绍请看CH559.H的 457行
*******************************************************************************/
#include "..\DEBUG.C" //调试信息打印
#include "..\DEBUG.H"
sbit led =P1^2;
sbit led2 =P2^4;
sbit led3 =P2^5;
#pragma NOAREGS
/*******************************************************************************
* Function Name : CH559GPIODrivCap(UINT8 Port,UINT8 Cap)
* Description : 端口0、1、2、3驱动能力设置
* Input : UINT8 Port端口选择(0、1、2、3)
UINT8 Cap驱动能力选择((0)5mA、(1)20mA(注意:P1口是10mA))
* Output : None
* Return : SUCCESS成功
FAIL失败
*******************************************************************************/
UINT8 CH559GPIODrivCap(UINT8 Port,UINT8 Cap)
{
if(Port >= 4){
return FAIL;
}
if(Cap == 0){ //驱动电流最大5mA
PORT_CFG &= ~(bP0_DRV << Port);//
}
else{
PORT_CFG |= (bP0_DRV << Port);//驱动电流最大20mA
}
return SUCCESS;
}
/*******************************************************************************
* Function Name : CH559GPIOModeSelt(UINT8 Port,UINT8 Mode,UINT8 PinNum)
* Description : 端口0、1、2、3引脚模式设置
* Input : UINT8 Port端口选择(0、1、2、3)
UINT8 Cap驱动方式选择(bPn_OC & Pn_DIR & Pn_PU)
0(000):仅输入,无上拉;
1(001):仅输入,带上拉;
2(01x):推挽输出,高低电平强驱动;
3(100):开漏输出,无上拉,支持输入;
4(110):开漏输出,无上拉,当转变输出由低到高时,仅驱动2个时钟的高电平
5(101):准双向(标准51模式),开漏输出,带上拉
6(111):准双向(标准51模式),开漏输出,带上拉,当转变输出由低到高时,仅驱动2个时钟的高电平
UINT8 PinNum(引脚选择0-7)
* Output : None
* Return : SUCCESS成功
FAIL失败
*******************************************************************************/
UINT8 CH559GPIOModeSelt(UINT8 Port,UINT8 Mode,UINT8 PinNum)
{
UINT8 Pn_DIR,Pn_PU;
if(Port >= 4){
return 0;
}
switch (Mode){
case 0: //仅输入,无上拉
PORT_CFG &= ~(bP0_OC << Port);//11111101
Pn_DIR &= ~(1<<PinNum);
Pn_PU &= ~(1<<PinNum);
break;
case 1: //仅输入,带上拉
PORT_CFG &= ~(bP0_OC << Port);
Pn_DIR &= ~(1<<PinNum);
Pn_PU |= 1<<PinNum;
break;
case 2: //推挽输出,高低电平强驱动
PORT_CFG &= ~(bP0_OC << Port);
Pn_DIR |= (1<<PinNum);
break;
case 3: //开漏输出,无上拉,支持输入
PORT_CFG |= (bP0_OC << Port);
Pn_DIR &= ~(1<<PinNum);
Pn_PU &= ~(1<<PinNum);
break;
case 4: //开漏输出,无上拉,当转变输出由低到高时,仅驱动2个时钟的高电平
PORT_CFG |= (bP0_OC << Port);
Pn_DIR |= 1<<PinNum;
Pn_PU &= ~(1<<PinNum);
break;
case 5: //弱准双向(标准51模式),开漏输出,带上拉
PORT_CFG |= (bP0_OC << Port);
Pn_DIR &= ~(1<<PinNum);
Pn_PU |= 1<<PinNum;
break;
case 6: //准双向(标准51模式),开漏输出,带上拉,当转变输出由低到高时,仅驱动2个时钟的高电平
PORT_CFG |= (bP0_OC << Port);
Pn_DIR |= 1<<PinNum;
Pn_PU |= 1<<PinNum;
break;
default:
break;
}
if(Port == 0){
P0_DIR = Pn_DIR;
P0_PU = Pn_PU;
}
if(Port == 1){
P1_DIR = Pn_DIR;
P1_PU = Pn_PU;
}
if(Port == 2){
P2_DIR = Pn_DIR;
P2_PU = Pn_PU;
}
if(Port == 3){
P3_DIR = Pn_DIR;
P3_PU = Pn_PU;
}
return 1;
}
/*******************************************************************************
* Function Name : CH559P4Mode()
* Description : CH559的P4端口初始化,P4默认是输入口
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH559P4Mode( )
{
P4_DIR |= 0xff; //置1设置为输出
P4_PU |= 0xff; //启动p4口内部上拉
P4_CFG |= bP4_DRV; //该位为0则P4口驱动能力5mA,为1时为20mA
}
/*******************************************************************************
* Function Name : CH559GPIOInterruptInit()
* Description : CH559GPIO中断初始化,其他引脚如P5.5\P1.4\P0.3\P5.7\P4.1\RXD0设置同理
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH559GPIOInterruptInit()
{
GPIO_IE &= ~bIE_IO_EDGE; //中断方式选择,该位为0则表示IO口电平中断,该位为1则表示IO口边沿中断
// GPIO_IE |= bIE_RXD1_LO; //使能RXD1引脚的中断,其他引脚中断设置同理
GPIO_IE |=bIE_P1_4_LO;//P14低电平触发
// GPIO_IE |=bIE_P5_5_HI;//电平模式高电平有效,边沿模式上升沿有效
// GPIO_IE |=bIE_P0_3_LO;//P03 low level / falling edge低电平触发40
// GPIO_IE |=bIE_P5_7_HI;//P57 high level / rising edge
// GPIO_IE |=bIE_P4_1_LO;//P41 low level / falling edge一直触发
// GPIO_IE |=bIE_RXD0_LO;//low level / falling edge P30
}
/*******************************************************************************
* Function Name : GPIOInterrupt(void)
* Description : GPIO 中断服务程序
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GPIOInterrupt( void ) interrupt INT_NO_GPIO using 1 //GPIO中断服务程序,使用寄存器组1
{
//RXD1_ = 1;
printf("P5_IN %02X\n",(UINT16)P5_IN); //bIO_INT_ACT为GPIO中断状态位
//IE_GPIO = 0;
printf("hello world!");
//使能GPIO中断、P2.6
}
void main( )
{
UINT16 value,value2;
// CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //等待内部晶振稳定
P4_DIR = 0xff;//设置P4.x为输出口
mInitSTDIO( ); //串口0,可以用于调试
printf("start ...\n");
XBUS_AUX |= bALE_CLK_EN; //关闭RS485模式 RS485_EN = 0;
SER1_IER |= bIER_PIN_MOD1| bIER_PIN_MOD0; //UART1 中断使能寄存器,脚位设置P2.6和P2.7,TNOW(P2.5)
// RXD1_ = 1;//P40
SCS =1;//P14上拉
CH559GPIOInterruptInit();
IE_GPIO = 1; //使能GPIO中断
EA = 1; //使能全局中断
CH559GPIODrivCap(1,1);//IO驱动功率P1口,10ma
CH559GPIODrivCap(2,1);//IO驱动功率P2口,20ma
value2=CH559GPIOModeSelt(1,2,2);//P1端口,推挽模式,P1.2
value =CH559GPIOModeSelt(2,2,4);//P2端口,推挽模式,P2.4
// CH559GPIOModeSelt(2,2,5);//P2端口,推挽模式,P2.5
led = 1;
led2= 1;
// led3 = 0;
while(1){
led = ~led;
led2= ~led2;
// led3 = ~led3;
printf("P24_value=%d ,P12_value=%d \n",value,value2);
mDelaymS( 1000 );
}
}



470

被折叠的 条评论
为什么被折叠?



