(2)GD32E502C-START 开发板学习——中断事件控制器

一、前言

        上一节简单介绍并实现点亮LED灯,本小节在此基础上加入中断事件控制器(EXTI),Cortex®-M33集成了嵌套式矢量型中断控制器(Nested Vectored Interrupt Controller(NVIC))来实现高效的异常和中断处理。中断系统实现了低延迟的异常和中断处理,且包含外部中断、定时器中断、DMA中断和串口中断等。

        本小节采用外部中断(外部信号发生高低电位变化触发中断),则选择GD32E502C-START 开发板上的按键KEY功能,当K2按键没按下时,GPIO引脚PA0被下拉电阻R29为低电平;反之,当K2按键按下后,GPIO引脚PA0为高电平。

        因此,通过检测GPIO引脚PA0的电平来触发中断,中断信号在传送到中断处理器(NVIC),中断处理器(NVIC)在中断向量表找到对应的中断服务函数地址,传送到CPU内核,CPU就会把当前运行的程序暂停,跳转到中断服务函数,等中断服务函数运行完后,再跳回到之前暂停的函数,理解文字不易理解,下图逻辑差不多就是这个概念,以及简单函数框架。

        比如:面前的你正在读我的文章,这时你的门被敲响(你点的外卖到了),你不得以被打断爱学习的你,马上起身开门拿外卖,并且吃了外卖后,再来继续读文章。

        所以,简单理解上面外部中断,比如LED灯先一直亮着,突然你按下按键KEY2及GPIO引脚PA0(高电平)触发中断,中断服务函数里编写的功能是关闭LED灯,松手后GPIO引脚PA0又变为(低电平),LED灯再次点亮。

        其次,中断事件还有优先级,在此就没具体介绍,每一个中断都有4位中断优先级配置位,可提供16个中断优先等级。其实简单理解就是多个中断/事件来临,根据这些中断/事件中优先级高低,依次运行函数,好比你吃外卖过程中女朋友电话打过来了,接女朋友电话事件比吃饭优先级高。

二、中断/事件控制器介绍

        接下里,简单说下中断/事件控制器,中断/事件可以分为硬件中断软件中断,硬件中断可以理解为外部或者内部信号的电位变化;软件中断可以理解为定时器计时、串口中断等,当达到了所设计的定时器时间来触发中断服务函数。

        上图很清楚的表示了中断线硬件引脚之间的关系,同一个EXTI线下的GPIO管脚不能同时触发,只能选择一个GPIO管脚作为该EXTI线的触发源,所有的0号引脚例如PA0/PB0/PC0等由0线代表,所有的1号引脚有1线表示以此类推。

三、实现功能及配置代码步骤

        接着上一节LED灯的功能扩展,当按键KEY按下时及4个LED灯点亮,按键KEY松开时及4个LED灯点熄灭。

        1、开启时钟(GPIO时钟和系统配置时钟)

        2、配置GPIO引脚模式及电平(LED灯、按键KEY)

        3、配置中断EXTI(GPIO复用连接EXTI源、中断模式、边沿触发、清除对应中断标志位)

        4、使能NVIC中断向量及优先级分组

        由于使用的引脚PA0(按键KEY),故对应的EXTI0_IRQn中断。

#include "gd32e502.h"
#include "systick.h"


void EXTI0_IRQHandler(void);   //中断函数定义声明
int key_count = 0;   //定义按键计数变量

int main(void)
{
  
    systick_config();   //初始化systick计数器  

    //********LED灯初始化**********//
    rcu_periph_clock_enable(RCU_GPIOA);    //打开GPIOA  GPIOF  GPIOC时钟
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOF);

    //设置GPIO模式   输出模式   带上拉电阻   GPIO_PIN_x
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_1);
    gpio_mode_set(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_5);
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1);

    //设置GPIO输出模式和速度   推完输出模式   最大输出速度50M   GPIO_PIN_x
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_1);
    gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_5);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_0 |GPIO_PIN_1);

    //电平置低  LED熄灭
    gpio_bit_reset(GPIOA, GPIO_PIN_1);
    gpio_bit_reset(GPIOF, GPIO_PIN_5);
    gpio_bit_reset(GPIOC, GPIO_PIN_0 | GPIO_PIN_1);
	//**************************//

   
    //********按键KEY灯初始化**********// 	
    //设置GPIO模式   输入模式   带上拉电阻   GPIO_PIN_x
    gpio_mode_set(GPIOA,GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_0);

    //设置AO口与中断线的映射关系
    syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0);

    //设置中断向量0为下降沿触发   中断模式
    exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_RISING);

    //清除中断向量0对应的标志位
    exti_interrupt_flag_clear(EXTI_0);
	//**************************//


    //********NVIC中断分组初始化**********// 
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  //中断向量等级为组别2
    nvic_irq_enable(EXTI0_IRQn, 2U, 2U);     //使能中断向量0  响应优先级2   抢占优先级2

    while(1)
    {
		
    }

}

void EXTI0_IRQHandler(void)
{
	//判断是否进入中断   RESET:不进入  RESET;进入
    if(RESET != exti_interrupt_flag_get(EXTI_0))   
	{
        delay_1ms(10);	//按键消抖
		//判断按键KEY是否按下
        if(SET == gpio_input_bit_get(GPIOA, GPIO_PIN_0))
        {
            key_count++;     //按键计数加1
			//按键长按进入while循环  
            while(SET == gpio_input_bit_get(GPIOA, GPIO_PIN_0)); 
	    }
		//设置按键2种功能功能    点亮LED  关闭LED
		if(key_count%2 == 1)
        {	
			//点亮LED灯
			gpio_bit_set(GPIOA, GPIO_PIN_1);
			gpio_bit_set(GPIOF, GPIO_PIN_5);
			gpio_bit_set(GPIOC, GPIO_PIN_0 | GPIO_PIN_1);
		}
		else
		{
			//关闭LED灯
			gpio_bit_reset(GPIOA, GPIO_PIN_1);
			gpio_bit_reset(GPIOF, GPIO_PIN_5);
			gpio_bit_reset(GPIOC, GPIO_PIN_0 | GPIO_PIN_1);
		}	
		//清除中断标志位  使下一次能够再次进入中断
		exti_interrupt_flag_clear(EXTI_0);
	}
}

四、效果展示

       间隔按下按键KEY2,LED灯点亮与熄灭切换,key_count按键计数累加,说明进入了EXTI0中断服务函数。

 预告:下一小节来实现PWM发波功能

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++实现SHA-1算法的示例代码: ```c++ #include <iostream> #include <iomanip> #include <sstream> #include <string> #include <cstring> #include <cstdint> // 左移循环移位 #define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) // SHA-1 常量 #define SHA1_K0 0x5A827999 #define SHA1_K1 0x6ED9EBA1 #define SHA1_K2 0x8F1BBCDC #define SHA1_K3 0xCA62C1D6 // SHA-1 初始化向量 const std::uint32_t SHA1_IV[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; // SHA-1 消息填充 void sha1_pad(std::string& message) { // 向消息尾部添加一个比特 1 message += '\x80'; // 添加 0 到 64 位填充,使消息长度满足模 512 余 448 std::size_t original_size = message.size(); std::size_t padding_size = (56 - (original_size % 64)) % 64; message.resize(original_size + padding_size, '\0'); // 在消息尾部添加 64 位的原始消息长度 std::uint64_t message_bits = original_size * 8; message.append(reinterpret_cast<const char*>(&message_bits), sizeof(message_bits)); } // SHA-1 压缩函数 void sha1_compress(std::uint32_t* state, const std::uint8_t* block) { // 初始化变量 std::uint32_t a = state[0]; std::uint32_t b = state[1]; std::uint32_t c = state[2]; std::uint32_t d = state[3]; std::uint32_t e = state[4]; std::uint32_t w[80]; // 将 16 个字分组成 80 个字 for (int i = 0; i < 16; i++) { w[i] = (block[i * 4] << 24) | (block[i * 4 + 1] << 16) | (block[i * 4 + 2] << 8) | block[i * 4 + 3]; } for (int i = 16; i < 80; i++) { w[i] = ROTL(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); } // SHA-1 主循环 for (int i = 0; i < 80; i++) { std::uint32_t f, k; if (i < 20) { f = (b & c) | ((~b) & d); k = SHA1_K0; } else if (i < 40) { f = b ^ c ^ d; k = SHA1_K1; } else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = SHA1_K2; } else { f = b ^ c ^ d; k = SHA1_K3; } std::uint32_t temp = ROTL(a, 5) + f + e + k + w[i]; e = d; d = c; c = ROTL(b, 30); b = a; a = temp; } // 更新状态 state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } // 计算 SHA-1 哈希值 std::string sha1(const std::string& message) { // 初始化状态 std::uint32_t state[5]; std::memcpy(state, SHA1_IV, sizeof(SHA1_IV)); // 对消息进行填充 std::string padded_message = message; sha1_pad(padded_message); // 对填充后的消息进行压缩 for (std::size_t i = 0; i < padded_message.size(); i += 64) { sha1_compress(state, reinterpret_cast<const std::uint8_t*>(&padded_message[i])); } // 将结果转换为十六进制字符串 std::ostringstream oss; oss << std::hex << std::setfill('0'); for (int i = 0; i < 5; i++) { oss << std::setw(8) << state[i]; } return oss.str(); } // 测试 int main() { std::cout << sha1("Hello, world!") << std::endl; // 0x7b502c3a1f48c860e3c0feeb6a1c9a22d1aee6cb return 0; } ``` 在该实现中,`sha1()` 函数接受一个字符串作为输入,并返回该字符串的 SHA-1 哈希值。哈希值以十六进制字符串的形式返回。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值