回调函数与位运算

简介: 在C语言中回调函数是函数指针的高级应用。所谓回调函数,一个笼统简单的介绍就是一个被作为参数传递的函数。从字面上看,回调函数的意思是:一个回去调用的函数,如何理解这句话呢?从逻辑上分析,要“回去”,必然存在着一个已知的目的地,然后在某一个时刻去访问;那么回调函数就是存在一个已知的函数体A,将这个函数体A的地址即函数名“A”(函数名即是这个函数体的函数指针,指向这个函数的地告知给另外某个函数B,当那个函数B执行到某一步的时候就会去执行函数A。

1. 回调函数

在C语言中回调函数是函数指针的高级应用。所谓回调函数,一个笼统简单的介绍就是一个被作为参数传递的函数。从字面上看,回调函数的意思是:一个回去调用的函数,如何理解这句话呢?从逻辑上分析,要“回去”,必然存在着一个已知的目的地,然后在某一个时刻去访问;那么回调函数就是存在一个已知的函数体A,将这个函数体A的地址即函数名“A”(函数名即是这个函数体的函数指针,指向这个函数的地告知给另外某个函数B,当那个函数B执行到某一步的时候就会去执行函数A。

首先是GPIO的回调函数声明:

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

可以看到其函数名是:HAL_GPIO_EXTI_Callback,形参是GPIO_Pin表示引脚号(Px0~Px15,x=A,B,C,D,E,F,G),从这个函数的名称出发,可以大致明确这是一个引脚的外部中断(EXTI)的回调函数。


然后大家看到前面还有个“__weak”,这是“弱函数”的修饰符,告诉编译器如果用户在其它地方用void

HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)重新定义了此回调函数那么优先调用用户定义的,否则调用这个弱函数修饰的回调函数。紧接着我们来看此回调函数是在哪里被调用的:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{ 
 /* EXTI line interrupt detected */
 if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u) 
 { 
 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); 
 HAL_GPIO_EXTI_Callback(GPIO_Pin); 
 } 
} 
  • 可以看到是在GPIO的外部中断服务函数中被调用的,与前面所说的这是一个外部引脚中断回调函数印证一致了。

  • GPIO的回调函数到此就说完了。其实STM32的HAL库中其它大多数的外设的回调函数基本都是如此,用户如果设计需求,就自己重定义需求的回调函数,然后在中断中被调用。

2. 位运算

位运算是指二进制位之间的运算。在嵌入式系统设计中,常常要处理二进制的问题,例如将某个寄存器中的某一个位置1或者置0,将数据左移5位等。

7795c3c87b37479e9539124a3dc96028.png

1. 按位与运算符(&)

参与运算的两个操作数,每个二进制位进行“与”运算,若两个都为1,结果为1,否者为0。

例如,1011&1001,第一位都为1,结果为1;第二位都为0,结果为0;第三位一个为1,一个为0,结果为0;第四位都为1,结果为1。最后结果为1001。


2. 按位或运算符(|)

参与运算的两个操作数,每个二进制位进行“或”运算,若两个都为0,结果为1,否者为1。

例如,1011 | 1001,第一位都为1,结果为1;第二位都为0,结果为0;第三位一个为1,一个为0,结果为1;第四位都为1,结果为1。最后结果为1011。


3. 按位取反运算符(~)

按位取反运算符用于对一个二进制数按位取反。

例如,~1011,第一位为1,取反为0;第二位为0,取反为1;第三位为1,取反为0,结果为1;第四位为1,取反为0。最后结果为0100。


4. 左移(<<)和右移(>>)运算符

左移(<<)运算符用于将一个数左移若干位,右移(>>)运算符用于将一个数右移若干位。

例如,假设val为unsigned char型数据,对应的二进制数为10111001。若val=va<<3,表示val左移3位,然后赋值给val,左移过程中,高位移出去后被丢弃,低位补0,最后val结果为11001000;若val=val>>3,表示val右移3位,然后赋值给val,右移过程中,低位移出去后被丢弃,高位补0,最后val结果为00010111。


5. 清0或置1

在嵌入式中,经常使用位预算符实现清0或置1。

例如,MCU的ODR寄存器控制引脚的输出电平高低,寄存器为32位,每位控制一个引脚的电平。假设需要控制GPIOB的1号引脚输出电平的高低,设置该寄存器第0位为1,输出高电平,设置该寄存器第0位为0,输出低电平。

#define GPIOB_ODR (*(volatile unsigned int *)(0x40010C0C))
GPIOB_ODR &= ~(1<<0);
GPIOB_ODR |= (1<<0);

第一行:使用#define定义了GPIOB_ODR 对应的内存地址为0x40010C0C。该地址为MCU的ODR寄存器地址。


第三行:GPIOB_ODR &= ~(1<<0)实际是GPIOB_ODR = GPIOB_ODR &~(1<<0),先将GPIOB_ODR和 ~(1<<0)的进行与运算,运算结果赋值给GPIOB_ODR。1<<0的值为00000000

00000000 00000000 00000001, 再取反为11111111 11111111 11111111 11111110,则GPIO_ODR的第0位和0与运算,结果必为0,其它位和1运算,由GPIO_ODR原来的值决定结果。这就实现了,只将GPIO_ODR的第0位清0,其它位保持不变的效果,实现了单独控制对应引脚电平输出低。


第四行:GPIOB_ODR |= (1<<0)实际是GPIOB_ODR = GPIOB_ODR | (1<<0),先将GPIOB_ODR和(1<<0) 的进行或运算,运算结果赋值给GPIOB_ODR。1<<0的值为00000000

00000000 00000000 00000001,则 GPIO_ODR的第0位和0或运算,结果必为1,其它位和0运算,由GPIO_ODR原来的值决定结果。这就实现了,只将GPIO_ODR的第0位置1,其它位保持不变的效果,实现了单独控制对应引脚电平输出高。

内容来源:百问网


相关文章
|
传感器
stm32f407探索者开发板(二十二)——通用定时器基本原理讲解
stm32f407探索者开发板(二十二)——通用定时器基本原理讲解
1576 0
|
传感器 数据采集 监控
基于阿里云MQTT服务,设计一个STM32的智能光伏控制系统
这篇文章详细介绍了利用STM32F103C8T6单片机实现光伏发电系统的关键技术。全文分为四章:第一章阐述了光伏发电的背景、意义及应用场景,强调其在绿色能源领域的重要性。第二章介绍了如何通过STM32F103C8T6及光敏电阻和伺服电机实现光线追踪系统,详细描述了硬件选择、连接及使用HAL库编写的单片机程序。第三章讲解了最大功率点追踪(MPPT)的原理,并展示了如何利用STM32F103C8T6和相关传感器、DC-DC转换器实现MPPT功能。第四章描述了如何通过STM32F103C8T6与SIM7600CE 4G模块连接到阿里云MQTT服务,实现设备状态数据的远程传输和控制。本文提供了全面的硬
18211 5
|
缓存 前端开发 JavaScript
前端工程化:Webpack与Gulp的构建工具选择与配置优化
【10月更文挑战第27天】在现代前端开发中,构建工具的选择对项目的效率和可维护性至关重要。本文比较了Webpack和Gulp两个流行的构建工具,介绍了它们的特点和适用场景,并提供了配置优化的最佳实践。Webpack适合大型模块化项目,Gulp则适用于快速自动化构建流程。通过合理的配置优化,可以显著提升构建效率和性能。
236 2
|
机器学习/深度学习 人工智能 TensorFlow
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【9月更文挑战第13天】本文将深入浅出地介绍卷积神经网络(CNN)的基本原理,并探讨其在图像识别领域的应用。通过实例演示如何利用Python和TensorFlow框架实现一个简单的CNN模型,我们将一步步从理论到实践,揭示CNN如何改变现代图像处理技术的面貌。无论你是深度学习新手还是希望深化理解,这篇文章都将为你提供价值。
|
JavaScript 前端开发 API
vue使用element plus组件上传服务器
vue使用element plus组件上传服务器
400 1
|
Python
【Python】已解决:(Python写入Excel表格报错)‘NoneType’ object has no attribute ‘write’
【Python】已解决:(Python写入Excel表格报错)‘NoneType’ object has no attribute ‘write’
1024 0
|
关系型数据库 MySQL Shell
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day2 全网最快最全(下)
黑马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day2 全网最快最全(下)
723 0
去掉Echarts饼状图的引导线
去掉Echarts饼状图的引导线
566 0
|
存储 网络安全 开发工具
Git的GUI图形化工具&ssh协议&IDEA集成Git
Git的GUI图形化工具&ssh协议&IDEA集成Git
416 0
|
Ubuntu 安全
ubuntu sudo apt-get upgrade 和 sudo apt-get dist-upgrade区别
ubuntu sudo apt-get upgrade 和 sudo apt-get dist-upgrade区别
344 0