起因介绍
因为公司之前用GD32F4和周立功的CSM300产品的一个SPI转CAN模块,做了个产品,其在收到CAN帧时INT引脚会为由高电平转为低电平。需要做一个中断接收的程序防止丢包。
GD32的外部中断介绍
◼ 高效的中断处理;
◼ 支持异常抢占和咬尾中断;
◼ 将系统从省电模式唤醒;
◼ 3 种触发类型:上升沿触发,下降沿触发和任意沿触发;
◼ 软件中断或事件触发;
◼ 可配置的触发源。
简单介绍下它的一些必备知识,后面我们能用得到的。
首先就是GD32的中断线
这个图很清楚的表示了中断线和硬件引脚之间的关系
即:所有的0号引脚例如PA0/PB0/PC0等由0线代表,所有的1号引脚有1线表示以此类推。
各系列外部中断的差异
软件配置
1. 时钟配置
不同系列的GD32单片机的时钟配置略有差别,
void rcu_config(void)
{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
rcu_periph_clock_enable(RCU_GPIOA);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
rcu_periph_clock_enable(RCU_GPIOA);
#if defined GD32F1X0 || GD32F3X0 || GD32E23X
rcu_periph_clock_enable(RCU_CFGCMP);
#elif defined GD32F4XX
rcu_periph_clock_enable(RCU_SYSCFG);
#endif
#endif
}
代码意思为,前两个if所判断的单片机只需要配置相应引脚所在的组的时钟就可以了,第三个if意思为开启RCU_CFGCMP时钟,第四个意思为开启系统时钟。
2. GPIO引脚的配置
对需要配置外部中断的引脚进行初始化
void gpio_config(void)
{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
#endif
}
主要区别就是不同系列单片机的初始化函数不同,一个是
gpio_init
一个是
gpio_mode_set
3. 外设配置
在代码中,首先使能
EXTI中断,之后配置EXTI源以及所需要的边沿,最后清除EXTI中断标志。
void exti_config(void)
{
#if defined GD32F10X_HD|| GD32F30X_HD || GD32F1X0 || GD32F20X_CL || GD32F4XX || GD32F3X0 || GD32E10X ||
GD32E23X
#if defined GD32F1X0 || GD32F3X0 || GD32E23X || GD32F4XX
#if defined GD32E23X
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(EXTI0_1_IRQn, 2U);
#elif defined GD32F4XX
nvic_irq_enable(EXTI0_IRQn, 2U,0U);
#elif defined GD32F1X0 || GD32F3X0
nvic_irq_enable(EXTI0_1_IRQn, 2U,0U);
#endif
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0);
/* configure key EXTI line */
exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_0);
#else
nvic_irq_enable(EXTI0_IRQn, 2U,0U);
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0);
/* configure key EXTI line */
exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_0);
#endif
#endif
}
这个意思也很清楚,根据不同系列单片机,选择不同语句,我这里用的是GD32F4系列所以使用到
//nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(EXTI5_9_IRQn, 2U, 0U);
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(EXTI_SOURCE_GPIOD, EXTI_SOURCE_PIN6);
/* configure key EXTI line */
exti_init(EXTI_6, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_6);
这四句话。
详细解读下重要语句
第一句,因为我这里用的是D6脚所以这里的中断号选择
EXTI5_9_IRQn
,后面参数参考上面的代码选择就可以了
第二句,这里需要配置为你所需要配置的外部中断引脚(我这里是D6脚)
第三句,因为我这里是D6脚,由上面那个表可知我们需要选择6号中断线即EXTI_6
第四句,清EXTI_6的中断标志位
4. 中断处理函数
void EXTI5_9_IRQHandler(void)
{
if(exti_interrupt_flag_get(EXTI_6) == SET)
{
//用户代码
exti_interrupt_flag_clear(EXTI_6);
}
}
因为我的中断号为
EXTI5_9_IRQn
所以我的中断函数名为
EXTI5_9_IRQHandler
工程示例
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "GPIO.h"
#include "SPI.h"
#include "CSM300.h"
/************************************************************************
GD32F407开发板实验:SPI通讯实验
技术支持:010-57273301
淘宝店铺:乾勤科技
官网:http://www.qianqin.com.cn/
作者: QianQin
*************************************************************************/
/************************************************************************
发送和接收数组组成
*第一个字节 帧头
*第二个字节 帧数据长度(除了帧头帧尾都算)
*第三个字节 帧类型 扩展帧为0x08 标准帧为0x00
*第四第五个字节 帧ID,此为标准帧ID仅有两个字节,扩展帧字节变为四个
*第六~十三字节 数据
*第十四字节 帧尾
******************************************************************************/
unsigned char send1[8]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
unsigned char send2[8]={0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11};
unsigned char get[14];
void initexit(void);
int main(void)
{
Gpio_Init();
systick_config();
rcu_config();
SPI0_Init();//SPI初始化
ConfigModule(); //配置CSM300芯片参数
Mode_Init();
initexit();
while(1)
{
delay_1ms(100);
Write_bytes(send1,0x555);//发数据测试
// delay_1ms(100);
// Write_bytes(send2,0x285);//发数据测试
//read_status();//读状态测试
/* 此为查询接收
//can卡发数据接收测试解除这部分函数屏蔽记得把前面的 delay_1ms(100); 给屏蔽
if(0==gpio_input_bit_get(GPIOD, GPIO_PIN_6))//检测INT脚是否为低电平
{
read_data(get);
}
*/
}
}
//外部中断初始化函数引脚为D6
void initexit(void)
{
rcu_periph_clock_enable(RCU_SYSCFG);
// rcu_periph_clock_enable(RCU_GPIOD);//要读取PC12的电平,需要开启RCU_GPIOC时钟
gpio_mode_set(RCU_GPIOD, GPIO_MODE_INPUT, GPIO_PUPD_NONE,GPIO_PIN_6);//将引脚PC12设为下拉输入
//nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(EXTI5_9_IRQn, 2U, 0U); //因为下面是EXTI_6所以这里要选EXTI5_9_IRQn,其中断函数就是EXTI5_9_IRQHandler
/* connect key EXTI line to key GPIO pin */
syscfg_exti_line_config(EXTI_SOURCE_GPIOD, EXTI_SOURCE_PIN6); //这边因为是D6脚所以要选EXTI_6 同理A4脚就是EXTI_4
/* configure key EXTI line */
exti_init(EXTI_6, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(EXTI_6);
}
//中断服务函数
void EXTI5_9_IRQHandler(void)
{
if (exti_interrupt_flag_get(EXTI_6) ==1)
{
read_data(get);
exti_interrupt_flag_clear(EXTI_6);
}
}