完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
位运算
有过oj刷题经验的童鞋对位运算应该不陌生,有很多算法基于位运算优化,同时由于计算机的数据存储是二进制,所以说用位操作二进制数很常见,这里简单的过一下 C中6种位操作如下 位设值 很多情况下,我们要不改变其他位的值的状况下,对某几个位进行设值。 方法就是先对需要设置的位用**&操作符进行清零操作,然后用|操作符设值。 比如要改变 GPIOA-> BSRRL 的状态,可以先对寄存器的值进行&**清零操作 GPIOA-> BSRRL &=0XFF0F; //将第 4-7 位清 0 然后再与需要设置的值进行**|**或运算 GPIOA-> BSRRL |=0X0040;//设置相应位的值,不改变其他位的值 移位 移位操作提高代码的可读性,移位操作在单片机开发中也非常重要,我们来看看下面一行代码 GPIOx->ODR = (((uint32_t)0x01) << pinpos); 这个操作就是将 ODR 寄存器的第 pinpos 位设置为 1,为什么要通过左移而不是直接设置一个固定的值呢? 其实,这是为了提高代码的可读性以及可重用性。这行代码可以很直观明了的知道,是将第 pinpos 位设置为 1。 如果写成 GPIOx->ODR =0x0030; 这样的代码就不好看也不好重用了。 取反 **~**取反操作使用技巧 SR 寄存器的每一位都代表一个状态,某个时刻我们希望去设置某一位的值为 0,同时 其他位都保留为 1,简单的作法是直接给寄存器设置一个值: TIMx->SR=0xFFF7; 这样的作法设置第 3 位为 0,但是这样的作法同样不好看,并且可读性很差。看看库函数代码中怎样使用的: TIMx->SR = (uint16_t)~TIM_FLAG; 而 TIM_FLAG 是通过宏定义定义的值: #define TIM_FLAG_Update ((uint16_t)0x0001) #define TIM_FLAG_CC1 ((uint16_t)0x0002) 看这个应该很容易明白,可以直接从宏定义中看出 TIM_FLAG_Update 就是设置的第 0 位了,可读性非常强。 宏 define 宏定义 define 是 C 语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。常见的格式: #define 标识符 字符串 “标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。例如: #define PLL_M 8 定义标识符 PLL_M 的值为 8。 至于 define 宏定义的其他一些知识,本质类似于查找替换,比如宏定义带参数这里我们就不多讲解。 ifdef 条件编译 单片机程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。 条件编译命令最常见的形式为: #ifdef 标识符 程序段 1 #else 程序段 2 #endif 它的作用是:当标识符已经被定义过(一般是用#define 命令定义),则对程序段 1 进行编译,否则编译程序段 2。 其中#else 部分也可以没有。 这个条件编译在MDK里面是用得很多的,在stm32f4xx.h这个头文件中经常会看到这样的代码。 关键字 extern 变量申明 extern在我的学习过程中用的很少,因为初学C的时候,就main.c一个文件,没有其他文件,而且代码量也很少,所以说这里简单的说明一下在STM32中C语言extern的用法 C 语言中 extern 可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。 这里面要注意,对于 extern 申明变量可以多次,但定义只有一次。在原子哥的代码中经常会看到看到这样的语句: extern u16 USART_RX_STA; 这个语句是申明USART_RX_STA变量在其他文件中已经定义了,在这里要使用到。 所以,你肯定可以找到在某个地方有变量定义的语句: u16 USART_RX_STA; 的出现。 下面通过两个例子说明一下使用方法。 在 Main.c 定义的全局变量 id,id 的初始化都是在 Main.c 里面进行的。 Main.c 文件 u8 id;//定义只允许一次 main() { id=1; printf("d%",id);//id=1 test(); printf("d%",id);//id=2 } 但是我们希望在main.c的 changeId(void) 函数中使用变量id,这个时候我们就需要在main.c里面去申明变量 id 是外部定义的了,因为如果不申明,变量 id 的作用域是到不了 main.c 文件中。看下面 main.c 中的代码: extern u8 id;//申明变量 id 是在外部定义的,申明可以在很多个文件中进行 void test(void) { id=2; } 在 main.c 中申明变量 id 在外部定义,然后在 main.c 中就可以使用变量 id 了。 再看如下网上的一个例子 #include int max(int x,int y); int main(void) { int result; /*外部变量声明*/ extern int g_X; extern int g_Y; result = max(g_X,g_Y); printf("the max value is %dn",result); return 0; } /*定义两个全局变量*/ int g_X = 10; int g_Y = 20; int max(int x, int y) { return (x>y ? x : y); } 代码中,全局变量 g_X 与 g_Y 是在 main 函数之后声明的,因此它的作用范围不在 main 函数中。如果我们需要在 main 函数中调用它们,就必须使用 extern 来对变量 g_X 与 g_Y 作“外部变量声明”,以扩展全局变量的作用域。也就是说,如果在变量定义之前要使用该变量,则应在使用之前加 extern 声明变量,使作用域扩展到从声明开始到本文件结束。 对于 extern 申明函数在外部定义的应用,这里我们就不多讲解了。 typedef 类型别名 typedef 用于为现有类型创建一个新的名字,或称为类型别名,用来简化变量的定义。 就是给数据类型起一个另外的名字,例如,我们在c语言定义一个64位整型,用long long,很长,这里我们就可这样写 typedef long long ll; ll a = 0; 而在C中,结构体变量的定义前面要加了一个struct关键字,很麻烦,用typedef就可以省略。 typedef 在 MDK 用得最多的就是定义结构体的类型别名和枚举类型了。 struct _GPIO { __IO uint32_t MODER; __IO uint32_t OTYPER; … }; 定义了一个结构体 GPIO,这样我们定义变量的方式为: struct _GPIO GPIOA;//定义结构体变量 GPIOA 但是这样很繁琐,MDK 中有很多这样的结构体变量需要定义。这里我们可以为结体定义一个别名 GPIO_TypeDef 这样我们就可以在其他地方通过别名 GPIO_TypeDef 来定义结构体变量了。 方法如下: typedef struct { __IO uint32_t MODER; __IO uint32_t OTYPER; … } GPIO_TypeDef; Typedef 为结构体定义一个别名 GPIO_TypeDef,这样我们可以通过 GPIO_TypeDef 来定义结构体变量: GPIO_TypeDef _GPIOA,_GPIOB; 这里的 GPIO_TypeDef 就跟 struct _GPIO 是等同的作用了。 在C中方便很多 结构体 在面向对象中,有类的概念,和C的结构体很像,大体上的思想类似,但是没有那么多的讲究 在MDK中太多地方使用结构体以及结构体指针,这里稍微提一下结构体的一些知识。 声明结构体类型: Struct 结构体名{ 成员列表; }变量名列表; 例如: Struct U_TYPE { Int BaudRate Int WordLength; }usart1,usart2; 在结构体申明的时候可以定义变量,也可以申明之后定义,方法是: Struct 结构体名字 结构体变量列表 ;例如: struct U_TYPE usart1,usart2; 结构体成员变量的引用方法是: 结构体变量名字.成员名 比如要引用 usart1 的成员 BaudRate,方法是:usart1.BaudRate; 结构体指针变量定义也是一样的,跟其他变量没有啥区别。 struct U_TYPE *usart3;//定义结构体指针变量 usart1; 结构体指针成员变量引用方法是通过“->”符号实现,比如要访问 usart3 结构体指针指向的结构体的成员变量 BaudRate,方法是: Usart3->BaudRate; 上面讲解了结构体和结构体指针的一些知识,其他的什么初始化这里就不多讲解了。 总结 没想到一个C语言复习模块写了这么多东西,不过还是很常用的,未完待续,=w= |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2956 浏览 16 评论
3458 浏览 1 评论
9000 浏览 16 评论
4051 浏览 18 评论
1109浏览 3评论
572浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2302浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1859浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 13:18 , Processed in 1.276603 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号