位操作主要用于在进行寄存器操作的时候,为了使实现某一功能而又不改变原来的功能所需要用到的一种按位运算的方法。比如我们要改变GPIOA->ODR的状态,一般来说需要两步,第一步,将原来位置的数据清除,第二步在将要存入的数据写入。
运算符 | 含义 | 运算符 | 含义 |
& | 按位与 | ~ | 取反 |
| | 安慰或 | << | 左移 |
^ | 按位异或 | >> | 右移 |
操作及其示例代码:
GPIOA->ODR &=0XFF0F;//将第4-7位清0。
GPIOA->ODR |=0X0040;//设置相应位的值,不改变其他位的值。
GPIOA->ODR |= 1<<5;//将ODR寄存器第五位设置位1,其他位置不变。
GPIOA->ODR = 0X0020;//这样也是第五位置1,但是其他位会强制清0,改变了原来的配置。
GPIOA->ODR &= 0XFFF7;//可读性不高,其实就是第3位清0,其他位置不变。
-》按位移来操作:
GPIOA->ODR |= ~(1<<3);//将第3位清0
如果有几位同时需要置1,可以取成8421码格式,来按整体位移。
注意:C语言中没有同或运算符。
define 时C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。
一般使用方法为:
#define 标识符 字符串(可以是常数、表达式、格式串等)
1 #define Author Yimiu 2 #define number 123
在声明之后就可以用标识符来代替原来的字符串或数字。
一般#ifdef语句要与#else、#end连用:即定义了情况一就编译程序段1,否则编译程序段2。
1 #ifndef condition1 2 //程序段1 3 #else 4 //程序段2 5 #endif
#ifndef、#define、#endif往往在头文件中使用,防止重复定义。
1 #ifndef __DELAY_H 2 #define __DELAY_H 3 //头文件及其函数声明 4 #endif
另外还有#if、#endif语句:满足condition1则编译程序段1,满足condition2则编译程序段2否则编译程序段3
1 #if condition1 2 //程序段1 3 #elseif condition2 4 //程序段2 5 #else 6 //程序段3 7 #endif
在C语言中extern可以放在函数声明或是变量声明之前,它的作用是提示编译器在遇到此变量和函数时在其他文件或是模块中寻找其定义,需要注意的是,对于变量或是函数的extern声明可以有很多次,但是变量或是函数的定义只能有一次。
1 extern void function(void); 2 extern u8 Author;
除了可以直接使用C提供的标准类型名(如int、char、float、double和long等)和程序员自己声明的机构提、共用体、美剧类型外,还可以用typedef制定新的类型名来代替已有的类型名。有以下两种情况:
1 typedef int integer;//指定用integer来做类型名,作用于int相同 2 typedef float Real;//指定用Real来做类型名,作用于float相同 3 integer a;//实际上就是int a
1 typedef struct 2 { 3 int month; 4 int day; 5 int year; 6 }Data; 7 //声明了一个新的类型名Date,来代表上边的结构体类型 8 Date birthday;//定义结构体类型变量birthday 9 Date *p; //定义结构体指针变量p,指向此结构体类型数据
1 typedef int Num[100];//声明Num为整型数组类型名 2 Num a; //定义a为整型数组名,它有一百个元素
1 typedef char *string; //声明string为字符指针类型 2 string p,s[10]; //声明p字符指针变量,s为字符指针数组
1 typedef int (*pointer)(); //声明pointer为指向函数的指针类型,该函数返回整型值 2 pointer p1,p2; //p1、p2为pointer类型指针变量
简单的说,就是按定义变量的方式,把变量名换上新类型名,并且在最前面加上“typedef”,就声明了新类型名代表原来的类型。
结构体声明:
1 struct struct_name 2 { 3 //成员列表 4 }; 5 stuct Student 6 { int number; 7 char name; 8 char sex; 9 int age; 10 float score; 11 };//注意分号 12 Student Yimiu;//定义了一个Yimiu结构体变量 13 //可以通过“.”来呼出变量成员 14 Yimiu.number = 092414216 15 Yimiu.name = yimi 16 //这样就为名为Yimiu的结构体变量成员赋值了
除了从变量的作用域(也就是空间上)来说的角度观察,分为全局变量和局部变量外,还可以从两外一个角度,即变量存在时间的长短(即生存期)角度来观察。有的变量在程序运行过程中都是存在的,而又的变量在则是在调用其所在函数时才会零时分配存储单元,当执行完毕后就会被释放,变量就不存在了。也就是说变量存储两种方式:静态存储方式和动态存储方式。静态存储方式是指在程序运行期间由系统分配固定的存储空间,而动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式。
static关键字为静态局部变量声明,用此关键字声明的变量在函数调用后不会消失而继续保留原值,也就是其占用的存储空间没有被释放,下一次调用该函数时,该变量已经有值(上一次运行结果)。
1 int func(int a) 2 { 3 suto int b=0; 4 static c=3; 5 b=b+1; 6 c=c+1; 7 return(a+b+c); 8 } 9 int main() 10 { 11 int a=2,i; 12 for(i=0;i<3;i++) 13 { 14 printf("%d\n\r",func(a)); 15 } 16 }//注意在STM32系列中主函数虽然为int型,但是不用返回函数值
运行的结果为7、8、9可以自行分析。
__weak关键字用来声明的函数叫做弱函数,我们可以这样理解,当应用层没有定义此函数时,那么系统默认编译此弱函数中的内容(系统必须要调用此函数),若我们在其他地方定义了没有用弱函数声明的函数时,此时就会编译我们自己定义的函数。其实当程序运行到某一函数时,系统先找其定义,若果没有再找其弱定义,最后都没有时会报错。
1 __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 2 { 3 /* Prevent unused argument(s) compilation warning */ 4 UNUSED(huart); 5 6 /* NOTE : This function should not be modified, when the callback is needed, 7 the HAL_UART_RxCpltCallback can be implemented in the user file 8 */ 9 } 10 ********************************************************************************* 11 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 12 { 13 #if EN_USART1_RX 14 if(huart->Instance==USART1)//如果是串口1 15 { 16 if((USART_RX_STA&0x8000)==0)//接收未完成 17 { 18 if(USART_RX_STA&0x4000)//接收到了0x0d 19 { 20 if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始 21 else USART_RX_STA|=0x8000; //接收完成了 22 } 23 else //还没收到0X0D 24 { 25 if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000; 26 else 27 { 28 USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ; 29 USART_RX_STA++; 30 if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 31 } 32 } 33 } 34 35 }
当我们不使用UART回调功能时,那么我们就不用写此函数,系统就会执行相应的弱定义函数,在整个工程当中,往往会有大量的弱函数被定义。
原文:https://www.cnblogs.com/vcan123/p/10421349.html