【雕爷学编程】Arduino 手册之变量修饰符volatile

在这里插入图片描述
在这里插入图片描述
什么是Arduino?
Arduino 是一款开源的电子原型平台,它可以让你用简单的硬件和软件来创建各种创意的项目。无论你是初学者还是专家,Arduino 都能为你提供无限的可能性。你可以用 Arduino 来控制传感器、灯光、马达、机器人、物联网设备等等,只要你能想到的,Arduino 都能帮你实现。

如果你想了解更多关于 Arduino 的信息,你可以访问 Arduino 的官方网站,那里有丰富的资源和教程供你参考。你也可以加入 Arduino 的社区,和来自世界各地的爱好者、学生、设计师和工程师交流心得和经验。此外,你还可以使用 Arduino 的在线编程工具,在云端编写代码并上传到你的开发板上。

Arduino 是一个不断发展和创新的平台,它有着广泛的应用领域和潜力。这里希望本手册能激发你对 Arduino 的兴趣和热情,让你享受 Arduino 带来的创造力和乐趣

在这里插入图片描述

维基百科的定义
Arduino 是一个开源嵌入式硬件平台,用来供用户制作可交互式的嵌入式项目。此外 Arduino 作为一个开源硬件和开源软件的公司,同时兼有项目和用户社群。该公司负责设计和制造Arduino电路板及相关附件。这些产品按照GNU宽通用公共许可证(LGPL)或GNU通用公共许可证(GPL)许可的开源硬件和软件分发的,Arduino 允许任何人制造 Arduino 板和软件分发。 Arduino 板可以以预装的形式商业销售,也可以作为 DIY 套件购买。

Arduino 2005 年时面世,作为意大利伊夫雷亚地区伊夫雷亚互动设计研究所的学生设计,目的是为新手和专业人员提供一种低成本且简单的方法,以建立使用传感器与环境相互作用的装置。初学者和爱好者可用Arduino制造传感器、简单机器人、恒温器和运动检测器等装置。

Arduino 这个名字来自意大利伊夫雷亚的一家酒吧,该项目的一些创始人过去常常会去这家酒吧。 酒吧以伊夫雷亚的 Arduin(Arduin of Ivrea)命名,他是伊夫雷亚边疆伯爵,也是 1002 年至 1014 年期间的意大利国王。

在这里插入图片描述

十一、Arduino变量的作用域 variable scope
在Arduino编程中,变量的作用域指的是变量在程序中可以被访问的范围。变量的作用域决定了它的可见性和生命周期。理解变量作用域对于编写清晰、可维护的代码至关重要。

Arduino变量的作用域有以下几种:
1)全局作用域(Global Scope):在函数之外声明的变量具有全局作用域,可以在整个程序中的任何位置被访问。这些变量在程序的生命周期内都是有效的。全局变量可以被多个函数共享,因此非常适合存储需要在多个函数中使用的数据。

2)局部作用域(Local Scope):在函数内部声明的变量具有局部作用域,只能在声明它们的函数内部被访问。这些变量在函数执行时创建,并在函数执行完毕后被销毁。局部变量通常用于存储临时数据或函数内部使用的数据。

3)块作用域(Block Scope):块作用域指的是由花括号({})包围的代码块内部声明的变量的作用域。这些变量只能在它们所在的块内部被访问,包括函数内部的if语句、for循环等。块作用域变量的生命周期仅限于其所在的块。

在应用场景上,你可以根据变量的作用域来选择合适的变量类型。全局变量适用于需要在多个函数中共享数据的情况,而局部变量则适用于函数内部的临时数据存储。通过正确使用变量的作用域,可以提高程序的可读性、可维护性和性能。

Arduino变量修饰符volatile
是一种用于声明变量的关键字,它表示该变量可能会被外部因素(如中断、硬件等)改变,而不是程序内部的逻辑。volatile修饰符的作用是告诉编译器不要对该变量进行优化,而是每次都从内存中读取或写入该变量的值。这样可以保证变量的值与实际情况一致,避免出现错误或不一致的情况。

volatile修饰符通常用于以下场景:
1)当变量需要在中断服务程序(ISR)中被修改时,例如计数器、标志位等。
2)当变量需要在多线程或多任务的环境中被共享时,例如信号量、互斥锁等。
3)当变量需要与硬件设备进行交互时,例如寄存器、端口等。

使用volatile修饰符时,需要注意以下事项:
1)volatile修饰符只能保证单个变量的原子性,即读取或写入该变量的操作不会被打断。如果需要保证多个变量的原子性,例如一个结构体或一个数组,那么需要使用其他方法,例如关闭中断、加锁等。
2)volatile修饰符不能保证变量的可见性,即其他线程或任务是否能及时看到该变量的最新值。如果需要保证可见性,那么需要使用其他方法,例如内存屏障、缓存刷新等。
3)volatile修饰符会影响编译器的优化效果,可能会降低程序的性能。因此,应该尽量减少使用volatile修饰符,只在必要的情况下使用。

以下是Arduino变量修饰符volatile的几个实际运用程序案例:

案例一:使用外部中断触发LED灯的闪烁

// 定义一个volatile类型的全局变量blinkFlag,用于表示是否闪烁LED灯
volatile bool blinkFlag = false;

// 定义一个外部中断服务程序(ISR),当按下按钮时,将blinkFlag置为true
void buttonPressed() {
  blinkFlag = true;
}

void setup() {
  // 设置LED灯引脚为输出模式
  pinMode(13, OUTPUT);
  // 设置按钮引脚为输入模式,并启用上拉电阻
  pinMode(2, INPUT_PULLUP);
  // 设置按钮引脚为外部中断源,并指定触发方式为下降沿
  attachInterrupt(digitalPinToInterrupt(2), buttonPressed, FALLING);
}

void loop() {
  // 如果blinkFlag为true,则闪烁LED灯,并将blinkFlag置为false
  if (blinkFlag) {
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    delay(500);
    blinkFlag = false;
  }
}

案例二:使用多任务调度器实现两个任务的并行执行

// 定义一个volatile类型的全局变量taskFlag,用于表示当前执行哪个任务
volatile int taskFlag = 0;

// 定义一个定时器中断服务程序(ISR),每隔一定时间切换任务
void timerISR() {
  // 如果当前执行任务0,则切换到任务1
  if (taskFlag == 0) {
    taskFlag = 1;
  }
  // 如果当前执行任务1,则切换到任务0
  else if (taskFlag == 1) {
    taskFlag = 0;
  }
}

void setup() {
  // 设置定时器中断,并指定触发周期为100毫秒
  Timer1.initialize(100000);
  Timer1.attachInterrupt(timerISR);
}

void loop() {
  // 如果taskFlag为0,则执行任务0,即打印"Task 0"
  if (taskFlag == 0) {
    Serial.println("Task 0");
    delay(500);
  }
  // 如果taskFlag为1,则执行任务1,即打印"Task 1"
  else if (taskFlag == 1) {
    Serial.println("Task 1");
    delay(500);
  }
}

案例三:使用串口通信接收数据,并在LCD显示屏上显示

// 定义一个volatile类型的全局变量data,用于存储接收到的数据
volatile char data = '\0';

// 定义一个串口接收中断服务程序(ISR),当接收到数据时,将其存入data变量
void serialEvent() {
  // 如果串口有可用数据,则读取一个字节,并存入data变量
  if (Serial.available()) {
    data = Serial.read();
  }
}

void setup() {
  // 初始化串口通信,并设置波特率为9600
  Serial.begin(9600);
  // 初始化LCD显示屏,并设置列数为16,行数为2
  lcd.begin(16, 2);
}

void loop() {
  // 如果data变量不为空,则在LCD显示屏上显示该数据,并将data变量清空
  if (data != '\0') {
    lcd.print(data);
    data = '\0';
  }
}

案例四:中断标志:

```cpp
volatile bool interruptFlag = false;  // 中断标志

void ISR() {
  interruptFlag = true;  // 中断服务子程序中修改中断标志
}

void loop() {
  if (interruptFlag) {
    // 处理中断事件
    // ...
    interruptFlag = false;  // 主程序中清除中断标志
  }
  // 其他任务
  // ...
}

在这个案例中,我们使用volatile关键字声明了一个中断标志变量interruptFlag。当中断服务子程序触发时,它会将中断标志置为true。在主程序的loop()函数中,我们检查中断标志是否为true,如果是,则执行中断事件处理,并在处理完毕后将中断标志重置为false。通过使用volatile修饰符,确保在不同的上下文中读取和修改中断标志的值时,能够获得最新的值。

案例五:多线程共享变量:

volatile int sharedValue = 0;  // 共享变量

void thread1() {
  while (true) {
    sharedValue++;  // 线程1中修改共享变量
    delay(1000);  // 延时1秒
  }
}

void thread2() {
  while (true) {
    int value = sharedValue;  // 线程2中读取共享变量
    // 使用共享变量进行其他操作
    // ...
    delay(500);  // 延时500毫秒
  }
}

void setup() {
  // 创建线程1和线程2
  // ...
}

void loop() {
  // 主程序循环
  // ...
}

在这个案例中,我们声明了一个共享变量sharedValue,并使用volatile关键字标记它。线程1负责每秒对共享变量进行加一操作,而线程2负责每500毫秒读取共享变量并进行其他操作。通过将共享变量声明为volatile,可以确保线程2在读取共享变量时获取到最新的值,避免数据不一致的问题。

案例六:外设寄存器通信:

volatile uint8_t *registerPtr = (uint8_t *)0x1234;  // 外设寄存器指针

void setup() {
  // 初始化外设
  // ...
}

void loop() {
  // 读取外设寄存器的值
  uint8_t value = *registerPtr;
  // 使用读取到的值进行其他操作
  // ...
  delay(1000);  // 延时1秒
}

在这个案例中,我们使用指针registerPtr来表示一个外设寄存器的地址。通过将指针声明为volatile,可以确保每次读取外设寄存器时都从内存中获取最新的值。在主程序的loop()函数中,我们读取外设寄存器的值,并在之后的操作中使用这个值。通过使用volatile修饰符,确保读取外设寄存器时不会使用缓存的值,而是始终获取最新的值。

这些案例展示了在Arduino中使用volatile变量修饰符的实际应用,涉及中断处理、多线程共享变量和外设寄存器通信。通过合理使用volatile,可以确保程序的正确性和可靠性。

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
雕爷学编程Arduino动手做寻迹的实验可以使用TCRT5000红外反射光电开关寻迹传感器模块。这个传感器模块可以通过检测周围的光反射来进行寻迹操作。你可以将这个模块连接到mBot的主控板mCore V1.5的RJ25接口上,因为mBot的主控板兼容Arduino系统,所以你可以使用Arduino编程语言来控制mBot进行寻迹操作。请参考【Arduino】168种传感器模块系列实验中的实验六十六,该实验详细介绍了如何使用TCRT5000红外反射光电开关寻迹传感器模块进行寻迹。祝你成功完成实验!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【雕爷学编程Arduino动手做(194)---makeblock mbot 主控板2](https://blog.csdn.net/weixin_41659040/article/details/132141677)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [【雕爷学编程Arduino动手做(65)---红外寻迹传感器](https://blog.csdn.net/weixin_41659040/article/details/106604080)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值