- 2025-01-06
-
回复了主题帖:
MCXN947 simple_match 例程 学习分享
Jacktang 发表于 2025-1-6 07:27
例程使用CTIMER(计数器/定时器模块)来实现一个简单的定时输出功能,这种功能还是方便些吧
有点像ST的标准定时器
- 2025-01-05
-
发表了主题帖:
MCXN947 simple_match 例程 学习分享
介绍
例程使用CTIMER(计数器/定时器模块)来实现一个简单的定时输出功能。具体来说,它设置了一个定时器,当计数器达到预设值时,会切换一个输出(在这个例子中是连接到LED的引脚),从而以固定的频率闪烁LED。
外设结构体配置
matchConfig.enableCounterReset = true;
matchConfig.enableCounterStop = false;
matchConfig.matchValue = CTIMER_CLK_FREQ / 2;
matchConfig.outControl = kCTIMER_Output_Toggle;
matchConfig.outPinInitState = true;
matchConfig.enableInterrupt = false;
CTIMER_SetupMatch(CTIMER, CTIMER_MAT_OUT, &matchConfig);
CTIMER_StartTimer(CTIMER);
外部匹配输出——当匹配寄存器(Match (MR0 - MR3))的值等于定时器计数器(Timer Counter, TC)的值时,该输出可以切换状态、变为低电平、变为高电平,或者不进行任何操作。外部匹配(EMR)控制这一输出的功能。您可以为多个引脚并行选择匹配输出功能。
/*!
* [url=home.php?mod=space&uid=159083]@brief[/url] 匹配配置
*
* 此结构体用于存储每个匹配寄存器的配置设置。
*/
typedef struct _ctimer_match_config
{
uint32_t matchValue; /*!< 存储在匹配寄存器中的值。当计数器达到此值时,会触发预设动作。 */
bool enableCounterReset; /*!< 是否在匹配时重置计数器。
- true: 将重置计数器。
- false: 不会重置计数器。 */
bool enableCounterStop; /*!< 是否在匹配时停止计数器。
- true: 将停止计数器。
- false:不会停止计数器。 */
ctimer_match_output_control_t outControl; /*!< 匹配时在输出使能位/输出上采取的动作。*/
bool outPinInitState; /*!< 输出使能位/输出的初始值。
- true: 初始状态为高电平。
- false: 初始状态为低电平。 */
bool enableInterrupt; /*!< 是否在匹配时生成中断。
- true: 匹配将生成中断。
- false: 匹配时不会生成中断。 */
} ctimer_match_config_t;
例程代码
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "board.h"
#include "fsl_ctimer.h"
#include <stdbool.h>
/*******************************************************************************
* Definitions
******************************************************************************/
#define CTIMER CTIMER0 /* Timer 0 */
#define CTIMER_MAT_OUT kCTIMER_Match_0 /* Match output 0 */
#define CTIMER_EMT_OUT (1u << kCTIMER_Match_0)
#define CTIMER_CLK_FREQ CLOCK_GetCTimerClkFreq(0U)
#define LED_RED1_INIT LED_RED_INIT
#define LED_RED1_ON LED_RED_ON
#define LED_RED1_OFF LED_RED_OFF
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief Main function
*/
int main(void)
{
ctimer_config_t config;
ctimer_match_config_t matchConfig;
/* Init hardware*/
/* attach FRO 12M to FLEXCOMM4 (debug console) */
CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u);
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
/* Use FRO HF clock for some of the Ctimers */
CLOCK_SetClkDiv(kCLOCK_DivCtimer0Clk, 1u);
CLOCK_AttachClk(kFRO_HF_to_CTIMER0);
BOARD_InitPins();
BOARD_InitBootClocks();
BOARD_InitDebugConsole();
#if defined(BOARD_HAS_NO_CTIMER_OUTPUT_PIN_CONNECTED_TO_LED)
LED_RED1_INIT(LOGIC_LED_OFF);
#endif
PRINTF("CTimer match example to toggle the output on a match\r\n");
CTIMER_GetDefaultConfig(&config);
CTIMER_Init(CTIMER, &config);
matchConfig.enableCounterReset = true;
matchConfig.enableCounterStop = false;
matchConfig.matchValue = CTIMER_CLK_FREQ / 2;
matchConfig.outControl = kCTIMER_Output_Toggle;
matchConfig.outPinInitState = true;
matchConfig.enableInterrupt = false;
CTIMER_SetupMatch(CTIMER, CTIMER_MAT_OUT, &matchConfig);
CTIMER_StartTimer(CTIMER);
while (1)
{
#if defined(BOARD_HAS_NO_CTIMER_OUTPUT_PIN_CONNECTED_TO_LED)
/* No timer match output pin connected to a LED
* toggle LED manually according to match status
*/
if (CTIMER_GetOutputMatchStatus(CTIMER, CTIMER_EMT_OUT))
{
LED_RED1_ON();
}
else
{
LED_RED1_OFF();
}
#endif
}
}
-
发表了主题帖:
基于NXP MCUXpresso SDK的GPIO控制与中断处理示例
[localvideo]5abca5892f45a06eeeed506b9a4b77c6[/localvideo]
引言
欢迎来到本次的技术分享!今天,我们将一起探讨一个基于NXP MCUXpresso SDK开发的GPIO(通用输入输出)控制与中断处理示例程序。这个程序展示了如何通过配置GPIO引脚来实现LED灯的闪烁以及按钮按下时的中断响应。
程序概述
该程序主要实现了以下功能:
LED灯控制:通过GPIO引脚控制板载LED灯的闪烁。
按钮中断处理:配置GPIO引脚为中断输入,当按钮被按下时,触发中断并响应相应的动作(如切换LED灯状态)。
关键组件与配置
外部中断号
一组GPIO 可以使能2个中断
ISF 中断状态标志
GPIO_PinGetInterruptFlag:读单个引脚的中断状态标志
#define GPIO_ICR_ISF_SHIFT (24U)
/*!
* brief Read individual pin's interrupt status flag.
*
* param base GPIO peripheral base pointer. (GPIOA, GPIOB, GPIOC, and so on)
* param pin GPIO specific pin number.
* return The current selected pin's interrupt status flag.
*/
uint8_t GPIO_PinGetInterruptFlag(GPIO_Type *base, uint32_t pin)
{
return (uint8_t)((base->ICR[pin] & GPIO_ICR_ISF_MASK) >> GPIO_ICR_ISF_SHIFT);
}
程序结构详解
头文件包含:
包含了必要的头文件,如fsl_debug_console.h用于调试输出,fsl_gpio.h用于GPIO控制等。
#include "fsl_debug_console.h"
#if defined(FSL_FEATURE_SOC_PORT_COUNT) && (FSL_FEATURE_SOC_PORT_COUNT)
#include "fsl_port.h"
#endif
#include "fsl_gpio.h"
#include "fsl_common.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
2.宏定义与变量声明:
定义了LED和按钮对应的GPIO引脚。
声明了用于标记按钮按下状态的变量。
3.中断服务函数实现:
*!
* @brief Interrupt service fuction of switch.
*
* This function toggles the LED
*/
void BOARD_SW_IRQ_HANDLER(void)
{
if(GPIO_PinGetInterruptFlag(GPIO0,6))
{
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
/* Clear external interrupt flag. */
GPIO_GpioClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
#else
/* Clear external interrupt flag. */
GPIO_PortClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
#endif
/* Change state of button. */
g_ButtonPress = true;
}
if(GPIO_PinGetInterruptFlag(GPIO0,29))
{
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
/* Clear external interrupt flag. */
GPIO_GpioClearInterruptFlags(GPIO0, 1U << 29);
#else
/* Clear external interrupt flag. */
GPIO_PortClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
#endif
/* Change state of button. */
g_ButtonPress1 = true;
}
if(GPIO_PinGetInterruptFlag(GPIO1,23))
{
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
/* Clear external interrupt flag. */
GPIO_GpioClearInterruptFlags(GPIO1, 1U << 23);
#else
/* Clear external interrupt flag. */
GPIO_PortClearInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
#endif
/* Change state of button. */
g_ButtonPress2 = true;
}
SDK_ISR_EXIT_BARRIER;
}
void GPIO10_IRQHandler(void)
{
if(GPIO_PinGetInterruptFlag(GPIO1,23))
{
/* Clear external interrupt flag. */
GPIO_GpioClearInterruptFlags(GPIO1, 1U << 23);
/* Change state of button. */
g_ButtonPress2 = true;
}
SDK_ISR_EXIT_BARRIER;
}
4.主函数实现:
/*!
* @brief Main function
*/
int main(void)
{
/* Define the init structure for the output LED pin*/
gpio_pin_config_t led_config = {
kGPIO_DigitalOutput,
0,
};
/* Define the init structure for the input switch pin */
gpio_pin_config_t sw_config = {
kGPIO_DigitalInput,
0,
};
/* Board pin, clock, debug console init */
/* attach FRO 12M to FLEXCOMM4 (debug console) */
CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u);
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
/* enable clock for GPIO*/
CLOCK_EnableClock(kCLOCK_Gpio0);
CLOCK_EnableClock(kCLOCK_Gpio1);
BOARD_InitPins();
BOARD_InitBootClocks();
BOARD_InitDebugConsole();
/* Print a note to terminal. */
PRINTF("\r\n GPIO Driver example\r\n");
PRINTF("\r\n The LED is blinking.\r\n");
GPIO_SetPinInterruptConfig(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, kGPIO_InterruptFallingEdge);
GPIO_SetPinInterruptConfig(GPIO0, 29, kGPIO_InterruptFallingEdge);
GPIO_SetPinInterruptChannel(GPIO0, 29,kGPIO_InterruptOutput0);
GPIO_SetPinInterruptConfig(GPIO1, 23, kGPIO_InterruptFallingEdge);
GPIO_SetPinInterruptChannel(GPIO1, 23,kGPIO_InterruptOutput0);
EnableIRQ(BOARD_SW_IRQ);
EnableIRQ(GPIO10_IRQn);
GPIO_PinInit(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, &sw_config);
GPIO_PinInit(GPIO0, 29, &sw_config);
GPIO_PinInit(GPIO1, 23, &sw_config);
GPIO_PinInit(BOARD_LED_GPIO, BOARD_LED_GPIO_PIN, &led_config);
GPIO_PinInit(GPIO0, 25, &led_config);
GPIO_PinInit(GPIO0, 26, &led_config);
while (1)
{
// delay();
// GPIO_PortToggle(BOARD_LED_GPIO, 1u << BOARD_LED_GPIO_PIN);
// GPIO_PortToggle(GPIO0, 1u << 25);
// GPIO_PortToggle(GPIO0, 1u << 26);
if (g_ButtonPress)
{
PRINTF(" %s is pressed \r\n", BOARD_SW_NAME);
/* Toggle LED. */
GPIO_PortToggle(BOARD_LED_GPIO, 1U << BOARD_LED_GPIO_PIN);
/* Reset state of button. */
g_ButtonPress = false;
}
if (g_ButtonPress1)
{
PRINTF(" %s is pressed \r\n", "GPIO0_29");
/* Toggle LED. */
GPIO_PortToggle(GPIO0, 1u << 25);
/* Reset state of button. */
g_ButtonPress1 = false;
}
if (g_ButtonPress2)
{
PRINTF(" %s is pressed \r\n", "GPIO0_23");
/* Toggle LED. */
GPIO_PortToggle(GPIO0, 1u << 26);
/* Reset state of button. */
g_ButtonPress2 = false;
}
}
}
附:源文件
- 2024-12-31
-
回复了主题帖:
【FRDM-MCXN947】移植LVGL
可以用GUIder 自动生成
- 2024-11-26
-
回复了主题帖:
给大家看看500多块钱的三合一的示波器表是啥东西·
wangerxian 发表于 2024-11-26 09:05
这个电压测量范围是多少?
哈哈,看你探头
- 2024-11-25
-
发表了主题帖:
给大家看看500多块钱的三合一的示波器表是啥东西·
本帖最后由 尹小舟 于 2024-11-25 20:55 编辑
双十一在这个店铺买了一个三合一的示波器表给大家看一看是什么东西
咋说呢,有比没有强,有钱可以买鼎阳804
- 2024-11-14
-
发表了主题帖:
国民技术N32G435 Flash时钟讨论
CPU 主频108M
flash 时钟来源内部16M RC时钟
内部有2KB iCache
CPU主频,读Flash要3个等待周期
他这个Flash 的时钟来源,感觉有一点奇怪
- 2024-11-03
-
回复了主题帖:
【Follow me第二季第2期】Arduino 基本任务 和 基于ArduinoHA SHT40数据上传HA
哈哈,一个评论也没有
- 2024-10-14
-
发表了主题帖:
常用的降低软件功耗的方法
采用高效率的算法可以有效地降低功耗,一些常用的方法
如下:
(1)用查表的方法代替实时的计算,尽量减少CPU的运算量。特别是在没有硬件浮点处理单元的MCU进行浮点处理时,直接用MCU进行浮点处理将会消耗大量的时间。将一些运算的结果预先算好,放在Fash存储器中,用查表的方法替代实时的计算,减少CPU的运算工作量,可以有效地降低CPU的功耗。很多微处理器都有快速有效的查表指令和寻址方式,用于优化查表算法。这种处理方法在离散余弦变换和A/D数据采集中能够带来可观的效率提升。
(2)对于不可避免的实时计算,应注意计算的精度,算到精度够了就应立即结束,避免“过度”的计算。在精度允许的情况下,使用简单函数代替复杂函数作近似运算,也是减少功耗的有效方法。
(3)尽量使用短的数据类型,如尽量使用字符型的8位数据替代16位的整型数据(4)尽量使用分数运算而避免浮点数运算等。
(5)用移位运算代替乘除法运算。采用MCU计算乘除法也是非常耗时的,如果采用左移和右移的办法来实现乘除法运算,将会减少运算时间。注意,除法的移位计算只能针对除
数比较特殊的情况。
(6)采用快速算法。在搜索算法中,使用二分搜索算法和分段查找算法的效率是不同的。从理论上可以估算,在1024个测量值的查找中,二分搜索最坏情况下10次可以查找到结果,顺序搜索最坏可能需要1024次。这在测量数值更多的情况下更为突出,一个高效率的查找算法有助于减小程序运行功耗。
(7)数字信号处理中的运算,采用FFT和快速卷积等,可以节省大量运算时间。
(8)一个程序使用中断方式还是查询方式,对于很多应用来说并不那么重要,但在软件低功耗设计特性上却相差甚远。例如,ADC在采集少量的数据时,MCU读取A/D转换数据可以采用查询方式或中断方式。查询方式和中断方式的低功耗特性相差甚远。使用中断方式,MCU可以什么都不做,甚至可以进入待机或停止模式。而采用查询方式,MCU必须不停地读取 /0端口寄存器,需要消耗很多额外的功耗。
(9)采用定时器。在程序中可以采用软件延时。但是,如果系统的定时器资源充裕,在需要定时的场合,最好采用硬件定时器,当定时器到了定时时间后,向MCU发出中断请求信号,这样可以减少MCU的工作时间,进而可以降低功耗。
(10)用宏代替子程序。在程序执行的过程中,读RAM需要比读Flash 更大的功耗。宏是在编译器预处理阶段进行替代,而在子程序的调用中MCU需要进行现场保护。在一次子程序调用中,因为CPU进入子程序时会首先将当前CPU存器推入堆栈(RAM),在离开时又将CPU存器弹出堆栈,这样至少对RAM有两次操作。对于程序设计来说,调用一个子程序还是一个宏,在程序写法上并没有什么不同,但宏会在编译时展开,CPU只是顺序执行指令,避免了调用子程序。唯一的问题是增加了代码的长度(代码量)。目前,MCU片内的Flash 空间越来越大,对于一些不在乎程序代码量大一些的应用,用宏代替子程序无疑可以降低系统的功耗。
摘自 ——————低功耗系统设计--原理、器件与电路
- 2024-10-07
-
上传了资料:
Follow me 第二季第2期任务 Arduino 代码
-
加入了学习《Follow me 第二季第2期任务提交》,观看 【得捷电子Follow me】提交视频
-
加入了学习《【Follow me第二季第1期】全部任务演示》,观看 全部任务演示2.0
- 2024-10-06
-
发表了主题帖:
【Follow me第二季第2期】Arduino 基本任务 和 基于ArduinoHA SHT40数据上传HA
项目演示视频
【Follow me第二季第2期】项目演示视频
物料展示
清单
Arduino UNO R4 WiFi
Qwiic缆线-50mm
SHT40温湿度传感器扩展板
10K电阻 * 2
6PIN 排针
1.Arduino UNO R4 WiFi 分析与介绍
UNO R4 WiFi采用了强大且非常稳健的瑞萨微控制器,该控制器也用于UNO R4 Minima上。瑞萨的微控制器以其高性能和稳健性而闻名,包括其内置的外设。这些外设包括模数转换器、定时器、脉冲宽度调制(PWM)单元、通信接口(例如UART、SPI和I2C)等。
1.1、核心规格
处理器:采用Renesas RA4M1(Arm Cortex®-M4)微控制器,运行速度为48MHz,相比UNO R3快3倍。
存储:SRAM从R3的2kB增加到32kB,闪存从32kB增加到256kB,以适应更复杂的项目需求。
工作电压:标准5V,但输入电压支持6V至24V,提供了更大的灵活性。
编程端口:USB-C接口,方便现代设备的连接。
1.2、特色功能
WiFi与蓝牙:内置Espressif S3 WiFi模块,支持WiFi和蓝牙连接,便于开发者创建物联网项目。
LED矩阵:板载一个12x8的红色LED矩阵(总共96个点),非常适合用于创意项目中的动画或数据可视化。
Qwiic连接器:提供一个行业标准的Qwiic I2C连接器,便于快速连接各种兼容模块,扩展开发板的功能。
新外设:包括12位模拟DAC、CAN总线、运算放大器和SWD端口等,增强了开发板的功能和灵活性。
1.3硬件探索
供电电路
主要有3种供电方式
开发板可以通过VIN引脚供电,支持6-24V的范围。
VIN引脚也连接到直流插孔(圆柱插头连接器)。
USB C口供电。
使用ISL8541102 降压型DC-DC芯片 将VIN的电压转换成5V电源,ISL8541102是瑞萨的一个宽输入,能提供1.2A电流能力的同步整流的降压芯片,封装很小,使用圣邦微SGM2205(线性稳压器)提供3.3V电源
USB CONNECTOR 电路
NLASB3157 是一个模拟开关用于切换USB C 是跟ESP32S3连接,还是R7FA4M1AB3CFM。
综合来看这个板子,应该是用ESP32给瑞萨MCU下载的。
2.基本任务
2.1入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld!
2.1.1 Blink LED闪灯
使用物料及外设:GPIO,一个板载LED
LED 使用的是Arduino 13号引脚。
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
2.1.2 串口打印Hello EEWorld!
使用物料及外设:GPIO,一个板载LED
void setup()
{
Serial.begin(9600);//设置波特率
Serial.println("Hello EEWorld!\r\n");//提示字符
}
void loop()
{
delay(5000);
Serial.println("Hello EEWorld!\r\n");
}
2.2 基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据曲线
2.2.1驱动12x8点阵LED
使用物料及外设:使用板载LED矩阵
UNO R4 WiFi 板载了一个12*8的红色LED矩阵,可以通过编程来控制这个矩阵以显示不同的图案、文字或动画。
该矩阵使用Charlieplexing将 96 个 LED 连接到仅 11 个 GPIO 端口(Arduino 表示法中的 D28 到 D38)。这种方式使用了很少的gpio端口就点亮了很多的LED灯, 因为像素由两个反并联连接的 LED 组成,并且像素共享端口。然而,由于人眼速度较慢,快速时间复用可以欺骗大脑看到完整的图像。
Arduino官方开发了一种工具,可以在浏览器中的 LED 矩阵上渲染的帧和动画。制作完动画之后,可以从工具中导出LED点阵数据。
单击此处转到 LED 矩阵工具。
制作完动画之后,你可以按照前面讨论过的格式,从工具中导出它们。
这里可以导出.h 文件
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
byte frame[8][12] = {
{ 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
uint32_t animation[] = {
0x400e015,
0x400400,
0x40040000
};
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
matrix.begin();
matrix.renderBitmap(frame, 8, 12);
delay(1000);
delay(1000);
frame[0][0] = 1;
matrix.renderBitmap(frame, 8, 12);
delay(1000);
delay(1000);
matrix.loadFrame(animation);
}
void loop() {
// put your main code here, to run repeatedly:
}
2.2.2用DAC生成正弦波
使用物料及外设:使用板载ADC DAC
Arduino R4可以直接使用wave生成正弦波
void setup() {
Serial.begin(500000);//设置波特率
Serial.println("Hello EEWorld!\r\n");//提示字符
wave.sine(freq);
wave.amplitude(0.5);
}
void loop() {
sensorValue = analogRead(A4);
Serial.println(sensorValue);
}
2.2.3用OPAMP放大DAC信号
使用物料及外设:2个10K电阻,板载放大器,ADC
#include "analogWave.h"
#include <OPAMP.h>
analogWave wave(DAC); // 使用DAC引脚实例化模拟曲线对象wave
float freq = 1; // 设置曲线初始频率
void setup() {
Serial.begin(2000000); // 串口波特率
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //设置OPAMP
wave.sine(freq); // 使用模拟曲线对象wave按照初始频率生成正弦波
wave.amplitude(0.5); //设置正弦曲线幅值为0.4
}
void loop() {
printf("%d\n",analogRead(A4)); // 读取DAC输出正弦值
Serial.print(" ");
printf("%d\n",analogRead(A5)); // 读取OPAMP输出正弦值
delay(100);
}
2.3 进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)
#include <ArduinoHA.h>
#include <Wire.h>
#include "WiFiS3.h"
#include "arduino_secrets.h"
int status = WL_IDLE_STATUS;
unsigned long lastUpdateAt = 0;
int freg=1;//max200 Hz imit by serial print
WiFiClient client;
HADevice device(MQTT_CLIENT_ID);//HADevice device (mac, sizeof (mac));
HAMqtt mqtt(client,device);
void setup() {
Serial.begin(9600);
wifi_and_mqtt_init();
}
void loop() {
mqtt.loop();
if ((millis() - lastUpdateAt) > 2000) { // update in 2s interval
lastUpdateAt = millis();
mqtt.publish(TOPIC_SUBSCRIBE,"Hi HA I'm Arduino UNO R4 WII");
}
}
void wifi_and_mqtt_init()
{
//check for the WiFi module:
////检查WiFi模块:
if(WiFi.status() == WL_NO_MODULE){
//WiFi模块通信失败
Serial.println("Communication with WiFi module failed!");
while(true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION){
Serial.println("Please upqrade the firmware");
}
//attempt to connect to WiFi network:
while(status!=WL_CONNECTED){
Serial.print("Attempting to connect to sID:");
Serial.println(SECRET_SSID);
//Connect to WPA/WPA2 network, change this line if using open or WEp network:
status =WiFi.begin(SECRET_SSID,SECRET_PASS);
delay(10000);
}
// mqtt.setDataPrefix("UNO");
if(!mqtt.begin(MQTT_SERVER,MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD)){
Serial.print("Failed,rc=");
Serial.print(mqtt.getState());
Serial.println("try again in f 5 seconds");
delay(5000);
}
printWifistatus();
}
void printWifistatus()
{
Serial.print("SSID:");
Serial.println(WiFi.SSID());
IPAddress ip= WiFi.localIP();
Serial.print("IP Address:");
Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength(RssI):");
Serial.print(rssi);
Serial.println("dBm");
}
3.扩展任务
3.1 SHT40传感器
SHT40传感器可以连接到Arduino UNO R4 WiFi Qwiic接口上,但需要注意几个关键点,以确保硬件的安全和正确的通信。
电压兼容性:
Qwiic接口仅支持3.3V供电。这意味着SHT40传感器和其他通过Qwiic连接器连接的设备都应设计为在3.3V下工作。
切勿尝试将5V或其他高于3.3V的电压连接到Qwiic接口,因为这可能会损坏您的Arduino R4板或其他连接的组件。
I2C总线选择:
Arduino R4可能具有多个I2C总线。由于Qwiic连接器连接到次级I2C总线(通常标记为IIC0或Wire1),您需要在代码中指定使用Wire1库来初始化这个特定的I2C总线。
使用Wire1.begin()而不是默认的Wire.begin()来初始化I2C通信。
Wier1在Wier.h 的声明
#if WIRE_HOWMANY > 0
extern TwoWire Wire;
#endif
#if WIRE_HOWMANY > 1
extern TwoWire Wire1;
#endif
#if WIRE_HOWMANY > 2
extern TwoWire Wire2;
#endif
#if WIRE_HOWMANY > 3
extern TwoWire Wire3;
#endif
在pins_arduino.h 的引脚定义
#define WIRE_HOWMANY 2
#define WIRE_SDA_PIN 18 /* A4 */
#define WIRE_SCL_PIN 19 /* A5 */
#define WIRE1_SDA_PIN 27
#define WIRE1_SCL_PIN 26
static const uint8_t SDA = WIRE_SDA_PIN;
static const uint8_t SCL = WIRE_SCL_PIN;
示例代码
22行,要改为 if (! sht4.begin(&Wire1))
/***************************************************
This is an example for the SHT4x Humidity & Temp Sensor
Designed specifically to work with the SHT4x sensor from Adafruit
----> https://www.adafruit.com/products/4885
These sensors use I2C to communicate, 2 pins are required to
interface
****************************************************/
#include "Adafruit_SHT4x.h"
Adafruit_SHT4x sht4 = Adafruit_SHT4x();
void setup() {
Serial.begin(115200);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit SHT4x test");
if (! sht4.begin(&Wire1)) {
Serial.println("Couldn't find SHT4x");
while (1) delay(1);
}
Serial.println("Found SHT4x sensor");
Serial.print("Serial number 0x");
Serial.println(sht4.readSerial(), HEX);
// You can have 3 different precisions, higher precision takes longer
sht4.setPrecision(SHT4X_HIGH_PRECISION);
switch (sht4.getPrecision()) {
case SHT4X_HIGH_PRECISION:
Serial.println("High precision");
break;
case SHT4X_MED_PRECISION:
Serial.println("Med precision");
break;
case SHT4X_LOW_PRECISION:
Serial.println("Low precision");
break;
}
// You can have 6 different heater settings
// higher heat and longer times uses more power
// and reads will take longer too!
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println("No heater");
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println("High heat for 1 second");
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println("High heat for 0.1 second");
break;
case SHT4X_MED_HEATER_1S:
Serial.println("Medium heat for 1 second");
break;
case SHT4X_MED_HEATER_100MS:
Serial.println("Medium heat for 0.1 second");
break;
case SHT4X_LOW_HEATER_1S:
Serial.println("Low heat for 1 second");
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println("Low heat for 0.1 second");
break;
}
}
void loop() {
sensors_event_t humidity, temp;
uint32_t timestamp = millis();
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
timestamp = millis() - timestamp;
Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");
Serial.print("Read duration (ms): ");
Serial.println(timestamp);
delay(1000);
}
3.2 STH40温湿度数据上传HA
#include <ArduinoHA.h>
#include <OPAMP.h>
#include <Wire.h>
#include "WiFiS3.h"
#include "arduino_secrets.h"
#include "Adafruit_SHT4x.h"
sensors_event_t humidity, temp;
Adafruit_SHT4x sht4 = Adafruit_SHT4x();
int status = WL_IDLE_STATUS;
unsigned long lastUpdateAt = 0;
int freg=1;//max200 Hz imit by serial print
WiFiClient client;
HADevice device(MQTT_CLIENT_ID);//HADevice device (mac, sizeof (mac));
HAMqtt mqtt(client,device);
HASensorNumber upSHT40_C_Sensor("SHT40_C");
HASensorNumber upSHT40_RH_Sensor("SHT40_RH");
void setup() {
Serial.begin(9600);
if (! sht4.begin(&Wire1)) {
Serial.println("Couldn't find SHT4x");
while (1) delay(1);
}
// You can have 3 different precisions, higher precision takes longer
sht4.setPrecision(SHT4X_HIGH_PRECISION);
switch (sht4.getPrecision()) {
case SHT4X_HIGH_PRECISION:
Serial.println("High precision");
break;
case SHT4X_MED_PRECISION:
Serial.println("Med precision");
break;
case SHT4X_LOW_PRECISION:
Serial.println("Low precision");
break;
}
// You can have 6 different heater settings
// higher heat and longer times uses more power
// and reads will take longer too!
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println("No heater");
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println("High heat for 1 second");
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println("High heat for 0.1 second");
break;
case SHT4X_MED_HEATER_1S:
Serial.println("Medium heat for 1 second");
break;
case SHT4X_MED_HEATER_100MS:
Serial.println("Medium heat for 0.1 second");
break;
case SHT4X_LOW_HEATER_1S:
Serial.println("Low heat for 1 second");
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println("Low heat for 0.1 second");
break;
}
wifi_and_mqtt_init();
device.setName("Arduino_SHT40_MY");
device.setSoftwareVersion("1.0.1");
upSHT40_C_Sensor.setIcon("mdi:home");
upSHT40_C_Sensor.setName("SHT40_C");
//upSHT40_C_Sensor.setUnitOfMeasurement("C");
upSHT40_RH_Sensor.setIcon("mdi:home");
upSHT40_RH_Sensor.setName("SHT40_RH");
// upSHT40_RH_Sensor.setUnitOfMeasurement("RH");
}
void loop() {
mqtt.loop();
if ((millis() - lastUpdateAt) > 2000) { // update in 2s interval
sht4.getEvent(&humidity, &temp);
upSHT40_RH_Sensor.setValue(humidity.relative_humidity);
upSHT40_C_Sensor.setValue(temp.temperature);
Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");
lastUpdateAt = millis();
mqtt.publish(TOPIC_SUBSCRIBE,"Hi EMQX I'm Arduino UNO R4 WII");
// you can reset the sensor as follows:
// analogSensor.setValue(nullptr);
}
}
void wifi_and_mqtt_init()
{
//check for the WiFi module:
////检查WiFi模块:
if(WiFi.status() == WL_NO_MODULE){
//WiFi模块通信失败
Serial.println("Communication with WiFi module failed!");
while(true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION){
Serial.println("Please upqrade the firmware");
}
//attempt to connect to WiFi network:
while(status!=WL_CONNECTED){
Serial.print("Attempting to connect to sID:");
Serial.println(SECRET_SSID);
//Connect to WPA/WPA2 network, change this line if using open or WEp network:
status =WiFi.begin(SECRET_SSID,SECRET_PASS);
delay(10000);
}
// mqtt.setDataPrefix("UNO");
if(!mqtt.begin(MQTT_SERVER,MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD)){
Serial.print("Failed,rc=");
Serial.print(mqtt.getState());
Serial.println("try again in f 5 seconds");
delay(5000);
}
printWifistatus();
}
void printWifistatus()
{
Serial.print("SSID:");
Serial.println(WiFi.SSID());
IPAddress ip= WiFi.localIP();
Serial.print("IP Address:");
Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength(RssI):");
Serial.print(rssi);
Serial.println("dBm");
}
4.ArduinoHA讲解补充
ArduinoHA是一个专为Arduino和ESP系列微控制器设计的开源库,其主要功能是实现这些设备与Home Assistant智能家居平台之间的无缝通信。使用MQTT(消息队列遥测传输)协议来完成通讯,MQTT是一种轻量级的、基于发布/订阅模式的消息传输协议,非常适合用于物联网(IoT)场景。
通过ArduinoHA库,开发者可以轻松地将Arduino或ESP设备集成到Home Assistant生态系统中,实现智能家居设备的智能化控制。这包括但不限于灯光控制、温湿度监测、门窗传感器、安防系统等。
ArduinoHA库提供了一系列API函数,用于设备的初始化、MQTT连接管理、设备状态更新以及处理来自Home Assistant的命令等。这些API函数使得开发者能够以简单、直观的方式编写代码,从而实现与Home Assistant的通信。
此外,ArduinoHA还支持MQTT自动发现功能,这意味着当设备首次连接到MQTT服务器时,它会自动向Home Assistant发送设备信息,从而避免了手动在Home Assistant中添加设备的繁琐过程。
使用方法与配置步骤:
1.连接到Home Assistant:
连接到WiFi网络。
初始化MQTT客户端并连接到MQTT服务器。
配置并添加设备到MQTT客户端。
在loop函数中处理MQTT消息并更新设备状态。
关键点:
全局初始化:
HADevice 和 HAMqtt 实例需要全局初始化,或者作为另一个全局对象的一部分进行初始化。
MQTT连接设置:
在Arduino的setup()逻辑结束时,需要调用HAMqtt::begin()方法。这个方法允许您提供MQTT代理(Broker)的IP地址和认证信息(如用户名和密码,如果有的话)。
MQTT循环处理:
HAMqtt::loop()方法需要被周期性地调用(不必在每个循环迭代中都调用)。这个方法负责处理MQTT通信中的接收和发送任务。
设备类型初始化:
设备类型(如传感器、开关等)需要在HAMqtt类之后进行初始化。关于如何初始化不同类型的设备,将在后面的文档中详细描述。
2.配置Home Assistant:
在Home Assistant中,无需手动添加设备,因为ArduinoHA支持MQTT自动发现。设备将自动出现在Home Assistant的设备列表中。
使用HADevice 配置设备信息
HADevice 类是一个用于表示将要注册到 Home Assistant 设备注册表中的设备的类。在智能家居自动化系统中,每个设备都会有一个唯一的标识符(ID),以便系统能够区分和控制它们。HADevice 类提供了构造函数来初始化设备对象,并允许设置设备的各种属性,如名称、制造商、型号等。
使用Device types API来设置实体信息
代码:>> 点击下载代码
项目总结
通过这次Follow me第二季第2期的活动,我有幸接触并深入学习了Arduino uNo R4 WIFI板卡的基本功能,以及HA物联网系统的搭建和ArduinoHA的相关知识。这次活动为我提供了一个宝贵的学习和实践机会,让我能够更深入地理解物联网技术及其在实际应用中的潜力。通过实际操作,成功搭建了一个简单的物联网系统,实现了对智能家居设备的远程控制和监控。学习了ArduinoHA的基本概念和工作原理,了解了其作为Arduino与HA系统之间的桥梁所发挥的重要作用。本次Follow me第二季第2期的活动让我收获颇丰。我不仅学到了许多新知识,还通过实际操作加深了对物联网技术的理解。未来,我将继续深入学习物联网领域的相关知识,不断提高自己的专业技能和实践能力,为未来的项目开发和研究打下坚实的基础。同时,我也期待能够有更多的机会参与类似的活动,与更多的同行交流和学习。
- 2024-10-05
-
加入了学习《FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解》,观看 Arduino UNO R4 Wi-Fi 及任务讲解
- 2024-10-03
-
加入了学习《【Follow me 第二季第2期任务】 各个任务实现的展示效果》,观看 【Follow me 第二季第2期任务】通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据
- 2024-09-23
-
加入了学习《【Follow me第二季第2期】+开发板硬件介绍和实现任务一 LED灯闪烁和串口打印》,观看 【Follow me第二季第2期】Arduino Uno R4 WiFi 通过MQTT连入Home Assistant
-
加入了学习《【Follow me第二季第2期】+开发板硬件介绍和实现任务一 LED灯闪烁和串口打印》,观看 【Follow me第二季第2期】+通过外部SHT40温湿度传感器,上传温湿度到HA
- 2024-09-13
-
回复了主题帖:
MCU嵌入式C代码编程规范
正点原子有一份,网上还有个华为的,还有些军工,航天的标准
- 2024-09-12
-
回复了主题帖:
【Follow me第二季第2期】传感器数据上传到HA
yangjiaxu 发表于 2024-9-11 11:52
这个HA是什么?是一个硬件吗还是一个什么东东呢?而且我看好像是一个物联网的系统
一个智能家居系统
- 2024-08-29
-
回复了主题帖:
锂电池供电的M0单片机,静太功耗5uA,有个引脚的连线有些奇怪,当手指靠近时功耗增大
外接上拉电阻会使功耗变大,所以尽量选用大电阻
手指的情况,IO口配置成输出,防止干扰