IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 单片机 C 语言基础(位操作、#define宏定义#ifdef条件编译、extern外部变量声明、enum枚举以及static静态变量) -> 正文阅读

[嵌入式]单片机 C 语言基础(位操作、#define宏定义#ifdef条件编译、extern外部变量声明、enum枚举以及static静态变量)

1.位操作

6种位操作运算符

在这里插入图片描述
&

口诀:有0出0,全1得1 (乘法)

0xAA = 1010 1010
0xFF = 1111 1111
1010 1010 & 1111 1111 = 1010 1010
GPIO->CRL &= 0xFF = 1010 1010

|

口诀:有1出1,全0得0(加法)

1010 1010 | 1111 1111 = 1111 1111

~

~ 1010 1010 = 0101 0101

按位异或^

口诀:值不一样为1,相同值为0

1010 ^ 1111 = 0101

左移<<

1010 左移 1位 0100

右移>>

1010 右移 1位 0101

实用技巧

例如:

GPIOA->CRL&=0XFFFFFF0F; //0XFFFFFF0F=1111 1111 1111 1111 1111 1111 0000 1111 将第 4-7 位清 0
GPIOA->CRL|=0X00000040; //设置相应位的值,不改变其他位的值 0X00000040=0000 0000 0000 0000 0000 0000 0100 0000 

这个场景单片机开发中经常使用,方法就是先对需要设置的位用&操作符进行清零操作,然后用|操作符设值。比如我要改变 GPIOA 的状态,可以先对寄存器的值进行&清零操作,然后再与需要设置的值进行|或运算。

GPIOA->ODR|=1<<5; //PA.5 输出高,不改变其他位

5 告诉我们是第 5 位也就是第 6 个端口,1 告诉我们是设置为 1 了。

#define TIM_FLAG ((uint16_t)0x0001)
TIMx->SR = (uint16_t)~TIM_FLAG;

设置第 0 位为 0。

2. define宏定义关键词

在这里插入图片描述

语法:#define 标识符 字符串

  • “标识符”为所定义的宏名
  • “字符串”可以是常数表达式格式串

例如:

#define SYSCLK_FREQ_72MHz 72000000

3. ifdef条件编译

单片机程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。

#ifdef 标识符
程序段 1
#else
程序段 2
#endif

作用是:当标识符已经被定义过(一般是用#define 命令定义),则对程序段 1 进行编译,否则编译程序段 2。 其中#else 部分也可以没有,即:

#ifdef
程序段 1
#endif

在 stm32f10x.h 这个头文件中经常会看到这样的语句:

#ifdef STM32F10X_HD
大容量芯片需要的一些变量定义
#endif

而 STM32F10X_HD 则是我们通过#define 来定义的。

扩展知识

if、ifdef、ifndef

//宏定义
#define WIN32 0
#define x64 1
#define SYSTEM WIN32

#if SYETEM == win32
printf(" win32\n");
#else
printf("x64\n");
#endif
#define DEBUG

#ifdef DEBUG
printf("输出调试信息\n");
#else
printf("不输出调试信息\n");
#endif

输出结果:输出调试信息

#define DEBUG

#ifndef DEBUG
printf("输出调试信息\n");
#else
printf("不输出调试信息\n");
#endif

输出结果:不输出调试信息

4. extern变量声明

C 语言中 extern 可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

注意,对于 extern 申明变量可以多次,但定义只有一次

例如:

在 Main.c 定义的全局变量 id,id 的初始化都是在 Main.c 里面进行的。

u8 id;//定义只允许一次
main()
{
id=1;
printf("d%",id);//id=1
test();
printf("d%",id);//id=2
}

但是我们希望在test.c中使用变量id,这个时候我们就需要在test.c里面去申明变量 id 是外部定义的了,因为如果不申明,变量 id 的作用域是到不了 test.c 文件中。看下面 test.c 中的代码:

extern u8 id;//申明变量 id 是在外部定义的,申明可以在很多个文件中进行
void test(void){
id=2;
}

5. typedefe类型别名

typedef 用于为现有类型创建一个新的名字,或称为类型别名,用来简化变量的定义。

typedef 在 MDK 用得最多的就是定义结构体的类型别名和枚举类型了。

可以为结体定义一个别名 GPIO_TypeDef,这样我们就可以在其他地方通过别名 GPIO_TypeDef 来定义结构体变量了。

方法如下:

typedef struct
{
 __IO uint32_t CRL;
 __IO uint32_t CRH;} GPIO_TypeDef;

Typedef 为结构体定义一个别名 GPIO_TypeDef。

GPIO_TypeDef _GPIOA,_GPIOB;

GPIO_TypeDef 就跟 struct _GPIO 是等同的作用了

6. struct 结构体

声明结构体类型:

Struct 结构体名{
成员列表;
}变量名列表;

例如:

Struct U_TYPE {
Int BaudRate
Int WordLength;
}usart1,usart2;

在结构体申明的时候可以定义变量(如上),也可以申明之后定义。

例如:

struct U_TYPE usart1,usart2;

结构体成员变量的引用方法是:结构体变量名字.成员名

例如:

usart1.BaudRate;

结构体指针变量定义

例如:

struct U_TYPE *usart3;//定义结构体指针变量 usart1;

结构体指针成员变量引用方法是通过“->”符号实现,比如要访问 usart3 结构体指针指向的结构体的成员变量 BaudRate。

例如:

Usart3->BaudRate;

7. enum 枚举

参考资料:enum(枚举)

定义枚举类型的同时定义枚举变量

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;

注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。

在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。

不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。

以下实例使用 for 来遍历枚举的元素:

#include <stdio.h>
 
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
int main()
{
    // 遍历枚举元素
    for (day = MON; day <= SUN; day++) {
        printf("枚举元素:%d \n", day);
    }
}

以上实例输出结果为:3

8. static关键字

参考:static变量及其作用

在 C 语言中,static 关键字不仅可以用来修饰变量,还可以用来修饰函数。

在使用 static 关键字修饰变量时,称此变量为静态变量

静态变量的存储方式与全局变量一样,都是静态存储方式。

但这里需要特别说明的是,静态变量属于静态存储方式属于静态存储方式的变量却不一定就是静态变量

例如,全局变量虽然属于静态存储方式,但并不是静态变量,它必须由static 加以定义后才能成为静态全局变量。

静态变量的作用:保持变量内容的持久性

有时候,我们希望函数中局部变量的值在函数调用结束之后不会消失,而仍然保留其原值。即它所占用的存储单元不释放,在下一次调用该函数时,其局部变量的值仍然存在,也就是上一次函数调用结束时的值。这时候,我们就应该将该局部变量用关键字 static 声明为“静态局部变量”。

例如:

#include <stdio.h>
void count();
int main(void)
{
    int i=0;
    for (i = 0;i <= 5;i++)
    {
            count();
    }
    return 0;
}
void count()
{
    /*声明一个静态局部变量*/
    static num = 0;
    num++;
    printf("%d\n",num);
}

在该代码中,我们通过在 count() 函数里声明一个静态局部变量 num 来作为计数器。因为静态局部变量是在编译时赋初值的,且只赋初值一次,在程序运行时它已有初值。以后在每次调用函数时就不再重新赋初值,而是保留上次函数调用结束时的值。这样,count() 函数每次被调用的时候,静态局部变量 num 就会保持上一次调用的值,然后再执行自增运算,这样就实现了计数功能。同时,它又避免了使用全局变量。


在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:44:59  更:2022-03-15 22:47:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:20:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码