活动介绍

完善以下代码 #define _LCD_Data sprintf #define _LCD_Buffer (char *)char_x sprintf(_LCD_Buffer,"jedkfsldz"); LCD_ShowString(30,210,100,240,24,_LCD_Buffer);

时间: 2024-02-17 14:00:10 浏览: 114
这段代码中,`_LCD_Data` 和 `_LCD_Buffer` 都是宏定义,它们的作用是简化代码中的字符串格式化操作。其中,`_LCD_Data` 宏定义了一个名为 `_LCD_Data` 的函数,其实质就是调用了 `sprintf` 函数。`_LCD_Buffer` 宏定义了一个名为 `_LCD_Buffer` 的字符数组,用于存储格式化后的字符串。 完善这段代码的过程中,需要修改 `_LCD_Buffer` 的定义,让它能够存储任意长度的字符串,而不是固定长度的字符串。可以将 `_LCD_Buffer` 定义为一个指针,然后在使用前根据需要进行内存分配。修改后的代码如下: ```c #define _LCD_Data sprintf char* _LCD_Buffer; _LCD_Buffer = (char*)malloc(100); // 分配 100 字节的内存 sprintf(_LCD_Buffer, "jedkfsldz"); LCD_ShowString(30, 210, 100, 240, 24, _LCD_Buffer); free(_LCD_Buffer); // 释放内存 ``` 这段代码在使用 `_LCD_Buffer` 前,先将其定义为一个指针,并分配了 100 字节的内存。然后使用 `sprintf` 函数将字符串格式化后存储到 `_LCD_Buffer` 中,最后将其传递给 `LCD_ShowString` 函数进行显示。注意,在使用完 `_LCD_Buffer` 后,需要使用 `free` 函数将其释放掉,以避免内存泄漏。
相关问题

完善以下代码 u8 i=9; #define _LCD_Data sprintf #define _LCD_Buffer (char *)char_x sprintf(_LCD_Buffer,"%d",i);

这段代码中,定义了一个整型变量 `i`,其值为 9。接下来使用了两个宏定义,`_LCD_Data` 和 `_LCD_Buffer`,其中 `_LCD_Data` 宏定义了一个名为 `_LCD_Data` 的函数,其实质就是调用了 `sprintf` 函数;`_LCD_Buffer` 宏定义了一个名为 `_LCD_Buffer` 的字符数组,用于存储格式化后的字符串。 这段代码的目的是将整型变量 `i` 转换为字符串,并存储到 `_LCD_Buffer` 中,最终将其传递给某个函数进行显示。但是,这段代码存在一些问题: 1. `_LCD_Buffer` 的定义不正确,应该是 `char*` 类型,而不是 `(char*)` 类型; 2. `sprintf` 函数的第二个参数应该是一个格式化字符串,指定了占位符的位置和类型,例如 `"%d"` 表示输出一个十进制整数; 3. 在使用完 `_LCD_Buffer` 后,需要使用 `free` 函数将其释放掉,以避免内存泄漏。 完善后的代码如下: ```c u8 i = 9; #define _LCD_Data sprintf char* _LCD_Buffer; _LCD_Buffer = (char*)malloc(20); // 分配 20 字节的内存 sprintf(_LCD_Buffer, "%d", i); LCD_ShowString(30, 210, 100, 240, 24, _LCD_Buffer); free(_LCD_Buffer); // 释放内存 ``` 这段代码中,将 `_LCD_Buffer` 定义为一个 `char*` 类型的指针,并分配了 20 字节的内存。使用 `sprintf` 函数将整型变量 `i` 转换为字符串,并存储到 `_LCD_Buffer` 中,最终将其传递给 `LCD_ShowString` 函数进行显示。注意,在使用完 `_LCD_Buffer` 后,需要使用 `free` 函数将其释放掉,以避免内存泄漏。

#include "stm32f10x.h" // Device header #include "Delay.h" #include "Key.h" #include "Led.h" #include "serial.h" #include "OLED.h" #include "Time.h" #include "Stack.h" static unsigned char Clear_Index=0; //清零检索 static unsigned char Count_Index=0; //计算检索 static uint32_t Index=0; static unsigned char Firmula[100]; //存储算数式子 static unsigned int Result; //存储结果 void USART1_IRQHandler(void); unsigned char a=19; int main(void) { Key_Init(); OLED_Init(); Serial_Init(); while(1) { if(Key_GetNum1()) //计算算数式 { Result=Deposit(Firmula); Count_Index=1; } if(Count_Index) //发送结果 { if(Key_GetNum2()) { printf("结果=%d",Result); OLED_ShowNum(1,1,Result,4); Index=0; Clear_Index=1; Count_Index=0; } } if(Clear_Index) //清零 { if(Key_GetNum3()) { Clear_Index=0; Init(); } } else if(!Clear_Index) { if(Key_GetNum3()) { printf("请输入运算式"); } } } } void USART1_IRQHandler(void) //串口中断函数 { Firmula[Index]=Serial_Getbyte(); printf("%c",Firmula[Index]); Index++; }#include "stm32f10x.h"// Device header #include "Stack.h" #include<ctype.h> #include "Serial.h" Stack_char Stack_CHAR; Stack_num Stack_NUM; uint8_t Push_char(Stack_char *stack,uint8_t CH); uint8_t Pop_char(Stack_char *stack,uint8_t *c); uint8_t Push_num(Stack_num *stack,unsigned int NUM); uint8_t Pop_num(Stack_num *stack,unsigned int *n); void Eval(void); uint16_t Priority(uint8_t ch); void Init(void) { Stack_NUM.top=0; Stack_CHAR.top=0; } uint16_t Priority(uint8_t ch) { switch(ch) { case '(' : case ')' : return 3; case '*' : case '/' : return 2; case '+' : case '-' : return 1; default : return 0; //分化优先级 } } uint32_t Deposit(uint8_t *String) { unsigned int i,j,index=0; uint8_t C; Init(); for(i = 0;String[i]!='\0'&&i < Stack_Size ;i++) { if(isdigit(String[i])) //判断是否 '0'<=string<='9' { index=0; j=i; for(;isdigit(String[j])&&j< Stack_Size;j++) { index=index*10+(String[j]-'0'); } Push_num(&Stack_NUM,index); i=j-1; //因为for循环多加了1,所以减去1 } else if(String[i]=='(') { Push_char(&Stack_CHAR,String[i]); } else if(String[i]==')') { while(Stack_CHAR.ch[Stack_CHAR.top] != '(') {Eval();} //直到遇到左括号,并且计算 if(Stack_CHAR.top != 0 && Stack_CHAR.ch[Stack_CHAR.top] == '(') { Pop_char(&Stack_CHAR,&C); //弹出左括号 } } else { while(Stack_CHAR.top!=0&&Stack_CHAR.ch[Stack_CHAR.top]!='('&&Priority(Stack_CHAR.ch[Stack_CHAR.top])>=Priority(String[i])) { Eval(); } Push_char(&Stack_CHAR,String[i]); } } while(Stack_CHAR.top) { Eval(); } //循环直至操作符为空 return Stack_NUM.num[Stack_NUM.top]; //此时数栈顶元素即为表达式值 } void Eval(void) { uint32_t a,x,b; uint8_t cha; Pop_num(&Stack_NUM,&b); Pop_num(&Stack_NUM,&a); //由于栈是陷进后出,与队列有区别(先进出) Pop_char(&Stack_CHAR,&cha); switch(cha) { case '*' : x=a*b;break; //计算 case '/' : { if(b==0) {printf("除数不能为0");x=0;} else {x=a/b;} break; } case '+' : {x=a+b;break;} case '-' : {x=a-b;break;} default :break; } Push_num(&Stack_NUM,x); } uint8_t Push_char(Stack_char *stack,uint8_t CH) { if(stack->top>=Stack_Size) { return 0; } stack->top++; stack->ch[stack->top]=CH; return 1; } uint8_t Push_num(Stack_num *stack,unsigned int NUM) { if(stack->top>=Stack_Size) { return 0; } stack->top++; stack->num[stack->top]=NUM; return 1; } uint8_t Pop_char(Stack_char *stack,uint8_t *c) { if(stack->top<=0) { return 0; } *c=stack->ch[stack->top]; stack->top--; return 1; } uint8_t Pop_num(Stack_num *stack,unsigned int *n) { if(stack->top<=0) { return 0; } *n=stack->num[stack->top]; stack->top--; return 1; } /* Copyright (C) ARM Ltd., 1999,2014 */ /* All rights reserved */ /* * RCS $Revision$ * Checkin $Date$ * Revising $Author: agrant $ */ #ifndef __stdint_h #define __stdint_h #define __ARMCLIB_VERSION 5060034 #ifdef __INT64_TYPE__ /* armclang predefines '__INT64_TYPE__' and '__INT64_C_SUFFIX__' */ #define __INT64 __INT64_TYPE__ #else /* armcc has builtin '__int64' which can be used in --strict mode */ #define __INT64 __int64 #define __INT64_C_SUFFIX__ ll #endif #define __PASTE2(x, y) x ## y #define __PASTE(x, y) __PASTE2(x, y) #define __INT64_C(x) __ESCAPE__(__PASTE(x, __INT64_C_SUFFIX__)) #define __UINT64_C(x) __ESCAPE__(__PASTE(x ## u, __INT64_C_SUFFIX__)) #if defined(__clang__) || (defined(__ARMCC_VERSION) && !defined(__STRICT_ANSI__)) /* armclang and non-strict armcc allow 'long long' in system headers */ #define __LONGLONG long long #else /* strict armcc has '__int64' */ #define __LONGLONG __int64 #endif #ifndef __STDINT_DECLS #define __STDINT_DECLS #undef __CLIBNS #ifdef __cplusplus namespace std { #define __CLIBNS std:: extern "C" { #else #define __CLIBNS #endif /* __cplusplus */ /* * 'signed' is redundant below, except for 'signed char' and if * the typedef is used to declare a bitfield. */ /* 7.18.1.1 */ /* exact-width signed integer types */ typedef signed char int8_t; typedef signed short int int16_t; typedef signed int int32_t; typedef signed __INT64 int64_t; /* exact-width unsigned integer types */ typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned __INT64 uint64_t; /* 7.18.1.2 */ /* smallest type of at least n bits */ /* minimum-width signed integer types */ typedef signed char int_least8_t; typedef signed short int int_least16_t; typedef signed int int_least32_t; typedef signed __INT64 int_least64_t; /* minimum-width unsigned integer types */ typedef unsigned char uint_least8_t; typedef unsigned short int uint_least16_t; typedef unsigned int uint_least32_t; typedef unsigned __INT64 uint_least64_t; /* 7.18.1.3 */ /* fastest minimum-width signed integer types */ typedef signed int int_fast8_t; typedef signed int int_fast16_t; typedef signed int int_fast32_t; typedef signed __INT64 int_fast64_t; /* fastest minimum-width unsigned integer types */ typedef unsigned int uint_fast8_t; typedef unsigned int uint_fast16_t; typedef unsigned int uint_fast32_t; typedef unsigned __INT64 uint_fast64_t; /* 7.18.1.4 integer types capable of holding object pointers */ #if __sizeof_ptr == 8 typedef signed __INT64 intptr_t; typedef unsigned __INT64 uintptr_t; #else typedef signed int intptr_t; typedef unsigned int uintptr_t; #endif /* 7.18.1.5 greatest-width integer types */ typedef signed __LONGLONG intmax_t; typedef unsigned __LONGLONG uintmax_t; #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) /* 7.18.2.1 */ /* minimum values of exact-width signed integer types */ #define INT8_MIN -128 #define INT16_MIN -32768 #define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ #define INT64_MIN __INT64_C(~0x7fffffffffffffff) /* -9223372036854775808 is unsigned */ /* maximum values of exact-width signed integer types */ #define INT8_MAX 127 #define INT16_MAX 32767 #define INT32_MAX 2147483647 #define INT64_MAX __INT64_C(9223372036854775807) /* maximum values of exact-width unsigned integer types */ #define UINT8_MAX 255 #define UINT16_MAX 65535 #define UINT32_MAX 4294967295u #define UINT64_MAX __UINT64_C(18446744073709551615) /* 7.18.2.2 */ /* minimum values of minimum-width signed integer types */ #define INT_LEAST8_MIN -128 #define INT_LEAST16_MIN -32768 #define INT_LEAST32_MIN (~0x7fffffff) #define INT_LEAST64_MIN __INT64_C(~0x7fffffffffffffff) /* maximum values of minimum-width signed integer types */ #define INT_LEAST8_MAX 127 #define INT_LEAST16_MAX 32767 #define INT_LEAST32_MAX 2147483647 #define INT_LEAST64_MAX __INT64_C(9223372036854775807) /* maximum values of minimum-width unsigned integer types */ #define UINT_LEAST8_MAX 255 #define UINT_LEAST16_MAX 65535 #define UINT_LEAST32_MAX 4294967295u #define UINT_LEAST64_MAX __UINT64_C(18446744073709551615) /* 7.18.2.3 */ /* minimum values of fastest minimum-width signed integer types */ #define INT_FAST8_MIN (~0x7fffffff) #define INT_FAST16_MIN (~0x7fffffff) #define INT_FAST32_MIN (~0x7fffffff) #define INT_FAST64_MIN __INT64_C(~0x7fffffffffffffff) /* maximum values of fastest minimum-width signed integer types */ #define INT_FAST8_MAX 2147483647 #define INT_FAST16_MAX 2147483647 #define INT_FAST32_MAX 2147483647 #define INT_FAST64_MAX __INT64_C(9223372036854775807) /* maximum values of fastest minimum-width unsigned integer types */ #define UINT_FAST8_MAX 4294967295u #define UINT_FAST16_MAX 4294967295u #define UINT_FAST32_MAX 4294967295u #define UINT_FAST64_MAX __UINT64_C(18446744073709551615) /* 7.18.2.4 */ /* minimum value of pointer-holding signed integer type */ #if __sizeof_ptr == 8 #define INTPTR_MIN INT64_MIN #else #define INTPTR_MIN INT32_MIN #endif /* maximum value of pointer-holding signed integer type */ #if __sizeof_ptr == 8 #define INTPTR_MAX INT64_MAX #else #define INTPTR_MAX INT32_MAX #endif /* maximum value of pointer-holding unsigned integer type */ #if __sizeof_ptr == 8 #define UINTPTR_MAX UINT64_MAX #else #define UINTPTR_MAX UINT32_MAX #endif /* 7.18.2.5 */ /* minimum value of greatest-width signed integer type */ #define INTMAX_MIN __ESCAPE__(~0x7fffffffffffffffll) /* maximum value of greatest-width signed integer type */ #define INTMAX_MAX __ESCAPE__(9223372036854775807ll) /* maximum value of greatest-width unsigned integer type */ #define UINTMAX_MAX __ESCAPE__(18446744073709551615ull) /* 7.18.3 */ /* limits of ptrdiff_t */ #if __sizeof_ptr == 8 #define PTRDIFF_MIN INT64_MIN #define PTRDIFF_MAX INT64_MAX #else #define PTRDIFF_MIN INT32_MIN #define PTRDIFF_MAX INT32_MAX #endif /* limits of sig_atomic_t */ #define SIG_ATOMIC_MIN (~0x7fffffff) #define SIG_ATOMIC_MAX 2147483647 /* limit of size_t */ #if __sizeof_ptr == 8 #define SIZE_MAX UINT64_MAX #else #define SIZE_MAX UINT32_MAX #endif /* limits of wchar_t */ /* NB we have to undef and redef because they're defined in both * stdint.h and wchar.h */ #undef WCHAR_MIN #undef WCHAR_MAX #if defined(__WCHAR32) || (defined(__ARM_SIZEOF_WCHAR_T) && __ARM_SIZEOF_WCHAR_T == 4) #define WCHAR_MIN 0 #define WCHAR_MAX 0xffffffffU #else #define WCHAR_MIN 0 #define WCHAR_MAX 65535 #endif /* limits of wint_t */ #define WINT_MIN (~0x7fffffff) #define WINT_MAX 2147483647 #endif /* __STDC_LIMIT_MACROS */ #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* 7.18.4.1 macros for minimum-width integer constants */ #define INT8_C(x) (x) #define INT16_C(x) (x) #define INT32_C(x) (x) #define INT64_C(x) __INT64_C(x) #define UINT8_C(x) (x ## u) #define UINT16_C(x) (x ## u) #define UINT32_C(x) (x ## u) #define UINT64_C(x) __UINT64_C(x) /* 7.18.4.2 macros for greatest-width integer constants */ #define INTMAX_C(x) __ESCAPE__(x ## ll) #define UINTMAX_C(x) __ESCAPE__(x ## ull) #endif /* __STDC_CONSTANT_MACROS */ #ifdef __cplusplus } /* extern "C" */ } /* namespace std */ #endif /* __cplusplus */ #endif /* __STDINT_DECLS */ #ifdef __cplusplus #ifndef __STDINT_NO_EXPORTS using ::std::int8_t; using ::std::int16_t; using ::std::int32_t; using ::std::int64_t; using ::std::uint8_t; using ::std::uint16_t; using ::std::uint32_t; using ::std::uint64_t; using ::std::int_least8_t; using ::std::int_least16_t; using ::std::int_least32_t; using ::std::int_least64_t; using ::std::uint_least8_t; using ::std::uint_least16_t; using ::std::uint_least32_t; using ::std::uint_least64_t; using ::std::int_fast8_t; using ::std::int_fast16_t; using ::std::int_fast32_t; using ::std::int_fast64_t; using ::std::uint_fast8_t; using ::std::uint_fast16_t; using ::std::uint_fast32_t; using ::std::uint_fast64_t; using ::std::intptr_t; using ::std::uintptr_t; using ::std::intmax_t; using ::std::uintmax_t; #endif #endif /* __cplusplus */ #undef __INT64 #undef __LONGLONG #endif /* __stdint_h */ /* end of stdint.h */ 在不改变原代码变量名情况下,实现小数点预算

<think>我们需要在现有的计算器程序中添加对小数点的支持。现有的代码只支持整数运算,我们需要修改以支持浮点数。 主要修改点: 1. 将操作数栈(Stack_num)的数据类型从unsigned int改为float(或double),以便存储小数。 2. 修改表达式解析过程,使其能够解析带小数点的数字。 3. 修改计算函数(Eval)以支持浮点运算。 4. 注意在显示和串口输出时,可能需要格式化输出浮点数。 但是,注意题目要求:不改变原代码变量名。因此,我们尽量保留原有的变量名,只修改类型和逻辑。 步骤: 1. 修改Stack_num结构体中的num数组为float类型(或double,但考虑到STM32资源,使用float可能更合适)。 2. 修改Push_num和Pop_num函数,使其操作float类型数据。 3. 在Deposit函数中,解析数字时,需要能够解析小数点。我们将整数部分和小数部分组合成一个浮点数。 4. 修改Eval函数,使用浮点数运算。 5. 修改主函数中Result的类型为float,并修改输出格式(printf和OLED显示)。 注意:原代码中使用了标准库的isdigit函数,我们还需要处理小数点。 具体修改: 1. 修改Stack.h中的栈定义: 原代码: typedef struct { unsigned int num[Stack_Size]; unsigned int top; }Stack_num; 改为: typedef struct { float num[Stack_Size]; // 改为浮点数 unsigned int top; }Stack_num; 2. 修改Stack.c中的Push_num和Pop_num函数,使其操作float类型。 3. 在Deposit函数中,解析数字的部分需要修改,以支持浮点数: 原整数解析: if(isdigit(String[i])) { index=0; j=i; for(;isdigit(String[j])&&j< Stack_Size;j++) { index=index*10+(String[j]-'0'); } Push_num(&Stack_NUM,index); i=j-1; } 改为浮点数解析: if(isdigit(String[i]) || String[i]=='.') // 注意,小数点开头的情况(如.5)也要考虑,但通常我们可能要求0.5,所以这里我们假设数字至少有一位数字,或者小数点后跟数字。 { float num = 0.0; float fraction = 0.1; int decimal = 0; // 标记是否遇到小数点 j = i; // 先处理整数部分 while (isdigit(String[j]) || (String[j]=='.' && !decimal)) { if (String[j]=='.') { decimal = 1; j++; break; } num = num * 10 + (String[j] - '0'); j++; } // 如果有小数部分 if (decimal) { while (isdigit(String[j]) && j < Stack_Size) { num += (String[j] - '0') * fraction; fraction *= 0.1; j++; } } Push_num(&Stack_NUM, num); i = j - 1; } 但是注意:上面的解析逻辑在遇到连续两个小数点时会出错。我们可以改进为: if(isdigit(String[i]) || String[i]=='.') { float num = 0.0; float base = 1.0; int decimal = 0; // 0表示整数部分,1表示小数部分 j = i; // 先处理整数部分(如果有) while (j < Stack_Size && (isdigit(String[j]) || String[j]=='.')) { if (String[j]=='.') { if (decimal) break; // 已经遇到小数点了,再次遇到则退出(错误情况,但这里简单处理为退出) decimal = 1; j++; continue; } if (!decimal) { num = num * 10 + (String[j] - '0'); } else { num += (String[j] - '0') * base; base *= 0.1; } j++; } Push_num(&Stack_NUM, num); i = j - 1; } 但是,上面的代码不能处理没有整数部分的小数(如.5)。为了支持这种情况,我们可以: if(isdigit(String[i]) || String[i]=='.') { float num = 0.0; float base = 1.0; int decimal = 0; j = i; // 先检查第一个字符是否是小数点 if (String[j]=='.') { decimal = 1; j++; } // 整数部分 while (j < Stack_Size && isdigit(String[j])) { num = num * 10 + (String[j] - '0'); j++; } // 如果接下来是小数点,且之前没有遇到小数点,则开始小数部分 if (String[j]=='.' && !decimal) { decimal = 1; j++; } // 小数部分 if (decimal) { float fraction = 0.1; while (j < Stack_Size && isdigit(String[j])) { num += (String[j] - '0') * fraction; fraction *= 0.1; j++; } } Push_num(&Stack_NUM, num); i = j - 1; } 但是,这样写比较复杂,而且可能不能处理多个小数点的情况。我们采用一个更通用的方法:先读取整个数字字符串(包括小数点),然后用atof或者自己解析。 由于我们是在嵌入式系统中,可能不想用atof(因为可能占用空间大),我们可以自己解析。 这里我们采用一个简单的方法:先计算整数部分,然后如果有小数点,再计算小数部分。 修改后的解析代码: if (isdigit(String[i]) || String[i] == '.') { char num_str[32]; // 临时存储数字字符串,假设数字长度不超过31 int k = 0; j = i; // 收集连续的数字和小数点 while (j < Stack_Size && (isdigit(String[j]) || String[j] == '.')) { // 如果遇到第二个小数点,则停止 if (String[j] == '.' && k > 0 && num_str[k-1] == '.') break; num_str[k++] = String[j++]; } num_str[k] = '\0'; // 字符串结束 // 转换为浮点数 float num = 0.0; int decimal_part = 0; float decimal_multiplier = 0.1; int has_decimal = 0; for (int m = 0; m < k; m++) { if (num_str[m] == '.') { has_decimal = 1; decimal_part = 1; continue; } if (!decimal_part) { num = num * 10 + (num_str[m] - '0'); } else { num += (num_str[m] - '0') * decimal_multiplier; decimal_multiplier *= 0.1; } } Push_num(&Stack_NUM, num); i = j - 1; } 但是,这个方法需要额外的字符数组,并且循环次数较多。考虑到嵌入式系统的资源,我们可以采用之前的分步解析,但改进以支持无整数部分的小数。 这里我们采用一个更高效的方法: if (isdigit(String[i]) || String[i] == '.') { float num = 0.0; float divisor = 1.0; // 用于小数部分的除数 int decimal_found = 0; // 是否遇到小数点 j = i; // 处理整数部分(如果有) if (isdigit(String[j])) { num = String[j] - '0'; j++; while (isdigit(String[j])) { num = num * 10 + (String[j] - '0'); j++; } } // 检查小数点 if (String[j] == '.') { decimal_found = 1; j++; } // 处理小数部分 if (decimal_found) { divisor = 10.0; while (isdigit(String[j])) { num += (String[j] - '0') / divisor; divisor *= 10.0; j++; } } // 还有一种情况:一开始就是小数点,那么整数部分为0,然后处理小数部分 if (String[i] == '.' && !isdigit(String[i])) { num = 0.0; j = i + 1; // 跳过小数点 divisor = 10.0; while (isdigit(String[j])) { num += (String[j] - '0') / divisor; divisor *= 10.0; j++; } } Push_num(&Stack_NUM, num); i = j - 1; } 但是,上面的代码在遇到第一个字符是小数点时,会进入第一个if吗?不会,因为第一个if的条件是:isdigit(String[i])为假,但String[i]=='.'为真,所以进入。 然后,第一个isdigit(String[j])(此时j=i)为假,所以整数部分跳过。然后遇到小数点(String[j]=='.'),设置decimal_found,然后j++,然后处理小数部分。 但是,此时如果小数点后面没有数字,那么小数部分循环不会执行,num还是0。这样,我们就把单独的小数点解析为0,这可能是错误的。所以,我们需要避免这种情况。 我们可以这样:如果遇到小数点,但后面没有数字,那么我们就认为这个小数点无效,不将其作为数字的一部分?但这样会破坏表达式。 实际上,在表达式中,单独的小数点是非法的。我们可以在解析时要求小数点后面至少有一个数字。 为了简单,我们假设输入是合法的。在非法输入时,程序可能会出错。 4. 修改Eval函数中的运算部分,使用浮点数。注意,除法现在要使用浮点除法,而且除数不能为0的检查仍然需要。 原代码: switch(cha) { case '*' : x=a*b;break; case '/' : { if(b==0) {printf("除数不能为0");x=0;} else {x=a/b;} break; } case '+' : {x=a+b;break;} case '-' : {x=a-b;break;} default :break; } 改为: switch(cha) { case '*' : x = a * b; break; case '/' : { if (b == 0) { printf("除数不能为0"); x = 0; } else { x = a / b; } break; } case '+' : x = a + b; break; case '-' : x = a - b; break; default : break; } 5. 修改主函数中的Result类型为float,并修改输出: 原代码: printf("结果=%d",Result); OLED_ShowNum(1,1,Result,4); 改为: printf("结果=%.2f",Result); // 保留两位小数 // OLED显示浮点数可能需要自己实现,因为原OLED_ShowNum可能只支持整数 // 我们可以添加一个显示浮点数的函数,或者将浮点数转换为字符串显示 由于原OLED_ShowNum只支持整数,我们需要修改显示部分。我们可以使用sprintf将浮点数格式化为字符串,然后用OLED_ShowString显示。 例如: char buf[20]; sprintf(buf, "%.2f", Result); // 保留两位小数 OLED_ShowString(1, 1, buf); 6. 另外,注意在串口接收中断中,我们接收的是字符,包括小数点,所以不需要修改。 7. 修改Init函数,将栈的top置0,这个不需要改。 8. 修改Pop_num和Push_num函数,使其操作float类型。 由于修改较多,我们需要确保所有使用到Stack_num的地方都改为float。 但是,注意题目要求不改变原变量名,所以我们只改变类型,变量名不变。 由于原代码中,栈操作函数都是通过指针操作栈结构体的,所以修改结构体成员类型后,函数内部也要修改。 例如,原来的: uint8_t Push_num(Stack_num *stack,unsigned int NUM) { if(stack->top>=Stack_Size) { return 0; } stack->top++; stack->num[stack->top]=NUM; return 1; } 改为: uint8_t Push_num(Stack_num *stack, float NUM) { if(stack->top>=Stack_Size) { return 0; } stack->top++; stack->num[stack->top] = NUM; return 1; } 同样,Pop_num也要修改: uint8_t Pop_num(Stack_num *stack, float *n) { if(stack->top<=0) { return 0; } *n = stack->num[stack->top]; stack->top--; return 1; } 9. 在Deposit函数中,变量a,x,b的类型也要改为float。 10. 注意,在表达式解析中,index变量原来是整数,现在改为float。 11. 由于浮点数有精度问题,我们需要注意比较时不要直接比较相等,但这里我们只做简单处理。 考虑到代码改动较大,我们逐步修改。 但是,由于原代码中使用了大量的unsigned int,我们需要将所有涉及操作数栈的地方改为float。同时,注意在计算过程中,都是浮点数运算。 由于原代码中Priority函数等不受影响,所以不需要修改。 总结修改步骤: 1. 修改Stack.h中的Stack_num结构体,将num数组改为float类型。 2. 修改Stack.c中Push_num和Pop_num的参数类型为float。 3. 修改Deposit函数中解析数字的部分,支持浮点数解析。 4. 修改Eval函数,使用float类型计算,并处理除0错误(注意浮点数除0不会导致异常,而是得到无穷大,但我们仍然可以检查并报错)。 5. 修改main函数中的Result为float类型,并修改输出为浮点数格式。 注意:浮点数输出在嵌入式系统中可能比较占用资源,特别是使用printf的浮点数格式化,这可能会增加代码量。如果资源紧张,可以考虑使用整数代替(乘以100等)或者使用简化版的浮点转字符串函数。 由于我们添加了浮点支持,需要确保编译器支持浮点数运算(通常默认支持),并且链接了相应的库。 最后,由于修改了栈的数据类型,其他使用到操作数栈的地方都要修改。目前,只有Deposit和Eval函数使用操作数栈。 下面,我们将修改后的代码列出(只列出修改的部分,因为原代码较长,我们只修改关键部分)。 注意:由于题目要求不改变原变量名,所以变量名我们都不变,只改变类型和部分逻辑。 由于代码较长,我们只给出修改后的关键函数,并省略未修改的部分。 修改Stack.h: typedef struct { float num[Stack_Size]; // 改为float unsigned int top; }Stack_num; 修改Stack.c: uint8_t Push_num(Stack_num *stack, float NUM) // 参数类型改为float { ... // 函数体不变,只是赋值给float数组 } uint8_t Pop_num(Stack_num *stack, float *n) // 改为float指针 { ... // 函数体不变 } 修改Deposit函数(在Stack.c中): uint32_t Deposit(uint8_t *String) // 注意,这个函数的返回类型现在是float?但是原函数返回uint32_t,我们需要改为float { // 但是,原函数返回类型是uint32_t,我们需要改为float,因为结果可能是小数。 // 所以修改函数返回类型为float } 但是,原函数声明在头文件中,也需要修改。 所以,我们修改Stack.h中的Deposit声明: float Deposit(uint8_t *String); 然后在Stack.c中修改Deposit函数: float Deposit(uint8_t *String) { // 将原来的index改为float类型?不需要,因为我们在解析时已经用局部变量存储了浮点数。 unsigned int i, j; float num_val; // 用于存储解析出的浮点数 // 删除原来的index,因为现在解析的是浮点数 ... // 其他变量定义 // 修改解析数字的代码段,使用上面讨论的解析方法(这里采用第二种方法,分整数和小数部分) // 具体实现我们采用支持无整数部分的方法: if (isdigit(String[i]) || String[i] == '.') { num_val = 0.0; int decimal_found = 0; float decimal_divisor = 10.0; // 小数部分的除数 j = i; // 如果第一个字符是小数点,则整数部分为0,并标记小数部分开始 if (String[j] == '.') { decimal_found = 1; j++; } else { // 解析整数部分 num_val = String[j] - '0'; j++; while (isdigit(String[j])) { num_val = num_val * 10 + (String[j] - '0'); j++; } // 检查是否有小数点 if (String[j] == '.') { decimal_found = 1; j++; } } // 解析小数部分 if (decimal_found) { while (isdigit(String[j])) { num_val += (String[j] - '0') / decimal_divisor; decimal_divisor *= 10.0; j++; } } Push_num(&Stack_NUM, num_val); i = j - 1; } ... // 其他部分不变 return Stack_NUM.num[Stack_NUM.top]; // 返回栈顶的浮点数 } 注意:在解析数字时,我们假设输入的数字字符串是合法的。如果遇到非法字符(如两个小数点),则解析会提前结束。 修改Eval函数: void Eval(void) { float a, b, x; // 改为float uint8_t cha; Pop_num(&Stack_NUM, &b); Pop_num(&Stack_NUM, &a); Pop_char(&Stack_CHAR, &cha); switch(cha) { ... // 改为浮点运算 } Push_num(&Stack_NUM, x); } 修改main.c: // 将Result改为float static float Result; // 在计算按键处理中 if(Key_GetNum1()) { Result = Deposit(Firmula); Count_Index=1; } // 在发送结果部分 if(Count_Index) { if(Key_GetNum2()) { // 使用sprintf将浮点数转为字符串,然后发送和显示 char buf[20]; sprintf(buf, "%.2f", Result); // 需要包含stdio.h printf("结果=%s", buf); OLED_ShowString(1,1,buf); // 假设有OLED_ShowString函数,如果没有,需要实现或使用其他方式显示 // 或者,如果OLED_ShowNum不支持浮点数,我们可以显示整数部分,但这样会丢失小数。所以最好实现OLED_ShowString。 // 如果之前没有OLED_ShowString,需要实现。 Index=0; Clear_Index=1; Count_Index=0; } } 注意:sprintf会占用较多资源,特别是浮点格式化。如果资源紧张,可以自己实现一个简单的浮点数转字符串函数。 另外,需要确保在工程设置中启用了浮点数支持(在printf中输出浮点数)。 由于改动较大,需要测试整数运算和浮点数运算。 最后,由于题目要求不改变原变量名,我们只改变了类型,变量名都保持不变。 以上是修改方案。由于代码较长,这里无法完整重写,但提供了详细的修改步骤和关键代码。</think>为了在现有代码中支持小数点运算而不改变变量名,需要进行以下关键修改: ### 核心修改方案: 1. **修改栈数据类型**(Stack.h): ```c // 原整数栈 typedef struct { unsigned int num[Stack_Size]; // 改为 float 类型 unsigned int top; } Stack_num; ``` 2. **数字解析逻辑**(Deposit函数): ```c if (isdigit(String[i]) || String[i] == '.') { float num_val = 0.0; float decimal_place = 0.1; int decimal_found = 0; j = i; while (isdigit(String[j]) || String[j] == '.') { if (String[j] == '.') { if (decimal_found) break; // 防止多个小数点 decimal_found = 1; j++; continue; } if (!decimal_found) { num_val = num_val * 10 + (String[j] - '0'); } else { num_val += (String[j] - '0') * decimal_place; decimal_place *= 0.1; } j++; } Push_num(&Stack_NUM, num_val); i = j - 1; } ``` 3. **运算函数改造**(Eval函数): ```c void Eval(void) { float a, b, x; // 改为浮点类型 Pop_num(&Stack_NUM, &b); Pop_num(&Stack_NUM, &a); Pop_char(&Stack_CHAR, &cha); switch(cha) { case '*': x = a * b; break; case '/': if (fabs(b) < 1e-6) { // 浮点零判断 printf("除数不能为0"); x = 0; } else { x = a / b; } break; case '+': x = a + b; break; case '-': x = a - b; break; } Push_num(&Stack_NUM, x); } ``` 4. **结果输出处理**(main函数): ```c // 修改Result类型 static float Result; // 输出时格式化为浮点数 printf("结果=%.2f", Result); OLED_ShowFloat(1, 1, Result, 2); // 需实现浮点显示函数 ``` ### 需要新增的OLED显示函数: ```c // OLED显示浮点数(示例) void OLED_ShowFloat(uint8_t line, uint8_t col, float num, uint8_t decimals) { char buf[20]; sprintf(buf, "%.*f", decimals, num); OLED_ShowString(line, col, buf); } ``` ### 关键注意事项: 1. **栈操作函数改造**: - 修改 `Push_num()` 和 `Pop_num()` 的参数类型为 `float` - 保留原函数名和参数名,仅修改数据类型 2. **除零处理优化**: 使用 `fabs(b) < 1e-6` 替代 `b == 0` 进行浮点零判断 3. **精度控制**: - 运算过程保持float精度 - 显示时通过 `%.2f` 控制小数位数 4. **输入验证**: 添加小数点合法性检查(禁止连续小数点) 此方案完整保留了所有原始变量名和函数名,仅通过修改数据类型和运算逻辑实现浮点支持。需注意在工程配置中启用浮点打印支持(`-u _printf_float` 链接器选项)。
阅读全文

相关推荐

#include #include #include #include #include #include #include #include #include #include #include #include #include <asm/uaccess.h> #include <asm/io.h> #include struct led_driver_data { uint32_t nr; uint32_t ng; uint32_t nb; uint32_t nw; uint32_t s1; uint32_t s2; uint32_t s3; uint32_t nr_flag; uint32_t ng_flag; uint32_t nb_flag; uint32_t nw_flag; uint32_t s1_flag; uint32_t s2_flag; uint32_t s3_flag; struct device *dev; }; struct led_driver_data *g_data; #define SPRD_LEDS_OF_DEVICE_ID_NAME "sprd,led_cpe" #define SPRD_LEDS_SYSFS_GROUP_NAME "led_cpe" #define LED_LOGI(fmt, ...)\ pr_info("[LED] %s:" fmt "", __func__, ##__VA_ARGS__) #define LED_LOGD(fmt, ...)\ pr_debug("[LED] %s:" fmt "", __func__, ##__VA_ARGS__) #define LED_LOGE(fmt, ...)\ pr_err("[LED] %s:" fmt "", __func__, ##__VA_ARGS__) static ssize_t nr_show(struct device *dev, struct device_attribute *attr, char *buf) { static uint32_t gpio_nr = 0; gpio_nr = gpio_get_value(g_data->nr); LED_LOGI("get gpio_nr=%d", gpio_nr); return sprintf(buf, "%d", gpio_nr); } static ssize_t nr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { static uint32_t gpio_nr = 0; if (kstrtouint(buf, 10, &gpio_nr) != 0) return -EINVAL; LED_LOGI("set gpio_nr=%d, count=%zu", gpio_nr, count); if(gpio_nr == 1) { gpio_set_value(g_data->nr, gpio_nr); } else if(gpio_nr == 0){ gpio_set_value(g_data->nr, gpio_nr); } return count; } static ssize_t ng_show(struct device *dev, struct device_attribute *attr, char *buf) { static uint32_t gpio_ng = 0; gpio_ng = g

#include <WiFi.h> #include #include "esp_camera.h" // WiFi配置 const char *ssid = "@PHICOMM_DC"; const char *password = "13625900271"; // 阿里云MQTT配置 const char* mqttHostUrl = "k1gy7PGezyP.iot-as-mqtt.cn-shanghai.aliyuncs.com"; const int mqttPort = 1883; const char* mqttUser = "esp32&k1gy7PGezyP"; const char* mqttPassword = "7c816276f8ad52225cc3a9c32dbbeaa62b511f7a6849058514cd4cf2c336c52f"; const char* clientId = "k1gy7PGezyP.esp32|securemode=2,signmethod=hmacsha256,timestamp=1742611788205|"; // 阿里云组包配置 #define PRODUCT_KEY "k1gy7PGezyP" #define DEVICE_NAME "esp32" #define ALINK_BODY_FORMAT "{\"id\":\"level\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":%s}" #define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post" // 摄像头配置 #define CAMERA_MODEL_AI_THINKER #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 void startCameraServer(); // 全局对象 WiFiClient espClient; PubSubClient client(espClient); unsigned long lastMs = 0; void setup() { Serial.begin(115200); Serial.setDebugOutput(true); // 初始化摄像头 camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sccb_sda = SIOD_GPIO_NUM; config.pin_sccb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.frame_size = FRAMESIZE_UXGA; config.pixel_format = PIXFORMAT_JPEG; config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_location = CAMERA_FB_IN_PSRAM; config.jpeg_quality = 12; config.fb_count = 1; if (psramFound()) { config.jpeg_quality = 10; config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed: 0x%x", err); return; } // 连接WiFi WiFi.begin(ssid, password); WiFi.setSleep(false); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi connected"); // 启动摄像头服务器 startCameraServer(); Serial.print("Camera Ready! Use: http://"); Serial.println(WiFi.localIP()); // 初始化MQTT client.setServer(mqttHostUrl, mqttPort); mqttCheckConnect(); } void loop() { client.loop(); if (millis() - lastMs >= 5000) { lastMs = millis(); if (!client.connected()) { mqttCheckConnect(); } mqttIntervalPost(); } } // MQTT连接检查 void mqttCheckConnect() { while (!client.connected()) { Serial.println("Connecting to MQTT..."); if (client.connect(clientId, mqttUser, mqttPassword)) { Serial.println("MQTT connected"); } else { Serial.print("Failed, rc="); Serial.print(client.state()); delay(2000); } } } // MQTT数据发送 void mqttIntervalPost() { char param[32]; char jsonBuf[128]; sprintf(param, "{\"num8\":%d}", 9); sprintf(jsonBuf, ALINK_BODY_FORMAT, param); client.publish(ALINK_TOPIC_PROP_POST, jsonBuf); Serial.println("Data sent: " + String(jsonBuf)); } 降低代码的功耗

#include <WiFi.h> #include #include "esp_camera.h" // WiFi配置 const char *ssid = "@PHICOMM_DC"; const char *password = "13625900271"; // 阿里云MQTT配置 const char* mqttHostUrl = "k1gy7PGezyP.iot-as-mqtt.cn-shanghai.aliyuncs.com"; const int mqttPort = 1883; const char* mqttUser = "esp32&k1gy7PGezyP"; const char* mqttPassword = "7c816276f8ad52225cc3a9c32dbbeaa62b511f7a6849058514cd4cf2c336c52f"; const char* clientId = "k1gy7PGezyP.esp32|securemode=2,signmethod=hmacsha256,timestamp=1742611788205|"; // 阿里云组包配置 #define PRODUCT_KEY "k1gy7PGezyP" #define DEVICE_NAME "esp32" #define ALINK_BODY_FORMAT "{\"id\":\"level\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":%s}" #define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post" // 摄像头配置 #define CAMERA_MODEL_AI_THINKER #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 void startCameraServer(); // 全局对象 WiFiClient espClient; PubSubClient client(espClient); unsigned long lastMs = 0; void setup() { Serial.begin(115200); Serial.setDebugOutput(true); // 初始化摄像头 camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sccb_sda = SIOD_GPIO_NUM; config.pin_sccb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.frame_size = FRAMESIZE_UXGA; config.pixel_format = PIXFORMAT_JPEG; config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_location = CAMERA_FB_IN_PSRAM; config.jpeg_quality = 12; config.fb_count = 1; if (psramFound()) { config.jpeg_quality = 10; config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed: 0x%x", err); return; } // 连接WiFi WiFi.begin(ssid, password); WiFi.setSleep(false); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi connected"); // 启动摄像头服务器 startCameraServer(); Serial.print("Camera Ready! Use: http://"); Serial.println(WiFi.localIP()); // 初始化MQTT client.setServer(mqttHostUrl, mqttPort); mqttCheckConnect(); } void loop() { client.loop(); if (millis() - lastMs >= 5000) { lastMs = millis(); if (!client.connected()) { mqttCheckConnect(); } mqttIntervalPost(); } } // MQTT连接检查 void mqttCheckConnect() { while (!client.connected()) { Serial.println("Connecting to MQTT..."); if (client.connect(clientId, mqttUser, mqttPassword)) { Serial.println("MQTT connected"); } else { Serial.print("Failed, rc="); Serial.print(client.state()); delay(2000); } } } // MQTT数据发送 void mqttIntervalPost() { char param[32]; char jsonBuf[128]; sprintf(param, "{\"num8\":%d}", 9); sprintf(jsonBuf, ALINK_BODY_FORMAT, param); client.publish(ALINK_TOPIC_PROP_POST, jsonBuf); Serial.println("Data sent: " + String(jsonBuf)); } 降低代码对硬件的消耗

#include < WiFi.h> #include < PubSubClient.h> #include “esp_camera.h” WiFi配置 const char *ssid = “@PHICOMM_DC”; const char *password = “13625900271”; 阿里云MQTT配置 const char* mqttHostUrl = “k1gy7PGezyP.iot-as-mqtt.cn-shanghai.aliyuncs.com”; const int mqttPort = 1883; const char* mqttUser = “esp32&k1gy7PGezyP”; const char* mqttPassword = “7c816276f8ad52225cc3a9c32dbbeaa62b511f7a6849058514cd4cf2c336c52f”; const char* clientId = “k1gy7PGezyP.esp32|securemode=2,signmethod=hmacsha256,timestamp=1742611788205|”; // 阿里云组包配置 #define PRODUCT_KEY “k1gy7PGezyP” #define DEVICE_NAME “ESP32” #define ALINK_BODY_FORMAT “{”id“:”level“,”version“:”1.0“,”method“:”thing.event.property.post“,”params“:%s}” #define ALINK_TOPIC_PROP_POST “/sys/” PRODUCT_KEY “/” DEVICE_NAME “/thing/event/property/post” // 摄像头配置 #define CAMERA_MODEL_AI_THINKER #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 无效 startCameraServer(); // 全局对象 WiFi客户端 espClient; PubSubClient 客户端 (espClient); 无符号 long lastMs = 0; 无效 setup() { 序列号.begin(115200); Serial.setDebugOutput(true); // 初始化摄像头 camera_config_t配置; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sccb_sda = SIOD_GPIO_NUM; config.pin_sccb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.frame_size = FRAMESIZE_UXGA; config.pixel_format = PIXFORMAT_JPEG; config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_location = CAMERA_FB_IN_PSRAM; config.jpeg_quality = 12; config.fb_count = 1; 如果 (psramFound()) { config.jpeg_quality = 10; config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf(“相机初始化失败:0x%x”, err); 返回; } 连接WiFi WiFi.begin(ssid, 密码); WiFi.setSleep(false); Serial.print(“连接到 WiFi”); while (WiFi.status() != WL_CONNECTED) { 延迟 (500); 序列号.print(“.”); } Serial.println(“\nWiFi 已连接”); // 启动摄像头服务器 startCameraServer(); Serial.print(“相机准备好了!用途:http:// 英寸); Serial.println(WiFi.localIP()); 初始化MQTT client.setServer(mqttHostUrl, mqttPort); mqttCheckConnect(); } void loop() { 客户端.loop(); 如果 (millis() - lastMs >= 5000) { lastMs = 毫(); 如果 (!client.connected()) { mqttCheckConnect(); } mqttIntervalPost(); } } MQTT连接检查 无效 mqttCheckConnect() { while (!client.connected()) { Serial.println(“正在连接到 MQTT...”); 如果 (client.connect(clientId, mqttUser, mqttPassword)) { Serial.println(“MQTT 已连接”); } else { Serial.print(“失败, rc=”); Serial.print(client.state()); 延迟(2000 年); } } } MQTT数据发送 无效 mqttIntervalPost() { char 参数[32]; 字符 jsonBuf[128]; sprintf(参数, “{”num8“:%d}”, 9); sprintf(jsonBuf, ALINK_BODY_FORMAT, param); client.publish(ALINK_TOPIC_PROP_POST, jsonBuf); Serial.println(“发送的数据: ” + String(jsonBuf)); } 降低代码的功耗

#include <driverlib.h> #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include "LCD_TFT_ILI9341.h" #include "Font_lib.h" #include "LCD_Display.h" #include "Segment_LED_Display.h" #include "SDCard.h" #include "TCA8418.h" #include "stdarg.h" #include "Hal_IIC.h" #include "Hal_Wheel.h" #include "HAL_wireUart.h" // 心率监测相关定义 #define NORMAL_LOW_THRESHOLD 60 // 正常心率下限 #define NORMAL_HIGH_THRESHOLD 100 // 正常心率上限 #define ADC_SAMPLE_INTERVAL 500 // ADC采样间隔(ms) // LED引脚定义 #define LED1 GPIO_PIN3 #define LED2 GPIO_PIN4 #define LED3 GPIO_PIN1 #define LED4 GPIO_PIN2 #define LED5 GPIO_PIN7 // ADC配置 - 使用数值代替未定义的宏 #define ADC_INPUT_PIN GPIO_PIN0 #define ADC_INPUT_PORT GPIO_PORT_P6 #define ADC_INPUT_CHANNEL 0 // A0通道 // ADC14配置常量 - 使用数值代替标识符 #define ADC_CLOCKSOURCE_SMCLK 0x00000000 #define ADC_PREDIVIDER_1 0x00000000 #define ADC_DIVIDER_1 0x00000000 #define ADC_RESOLUTION_14BIT 0x00000003 #define ADC_MEM0 0 #define ADC_VREFPOS_AVCC 0x00000000 #define ADC_VREFNEG_VSS 0x00000000 #define ADC_PULSE_WIDTH_192 0x00000003 // GPIO配置常量 #define GPIO_ANALOG_MODE 0x00000000 // 模拟模式 // ADC采样模式常量 #define ADC_MANUAL_MODE 0x00000000 // 手动采样模式 //***************************************************************************** // //XT1 Crystal Frequency being used // //***************************************************************************** #define UCS_XT1_CRYSTAL_FREQUENCY 32768 //***************************************************************************** // //Target frequency for MCLK in kHz // //***************************************************************************** #define UCS_MCLK_DESIRED_FREQUENCY_IN_KHZ 20000 //***************************************************************************** // //MCLK/FLLRef Ratio // //***************************************************************************** #define UCS_MCLK_FLLREF_RATIO 625 //***************************************************************************** // //Variable to store returned STATUS_SUCCESS or STATUS_FAIL // //***************************************************************************** uint8_t returnValue = 0; //***************************************************************************** // //Variable to store status of Oscillator fault flags // //***************************************************************************** uint16_t status; // 全局变量 uint16_t heart_rate = 0; // 存储心率值 bool heart_rate_display = false; // 心率显示标志 bool alert_flag = false; // 报警标志 uint32_t last_adc_time = 0; // 上次ADC采样时间 uint32_t blink_timer = 0; // LED闪烁计时器 bool led_blink_state = false; // LED闪烁状态 void short_delay(void) { //Delay 0.5s __delay_cycles(1000000); } // ADC初始化函数 - 使用数值常量 void ADC_init(void) { // 配置ADC输入引脚(P6.0)为模拟模式 GPIO_setAsPeripheralModuleFunctionInputPin( ADC_INPUT_PORT, ADC_INPUT_PIN, GPIO_ANALOG_MODE // 使用模拟模式 ); // 初始化ADC14模块 ADC14_enableModule(); ADC14_initModule(ADC_CLOCKSOURCE_SMCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1, ADC_RESOLUTION_14BIT); // 配置ADC存储寄存器 ADC14_configureSingleSampleMode(ADC_MEM0, true); ADC14_configureConversionMemory(ADC_MEM0, ADC_VREFPOS_AVCC | ADC_VREFNEG_VSS, ADC_INPUT_CHANNEL, false); // 设置采样周期 ADC14_setSampleHoldTime(ADC_PULSE_WIDTH_192, ADC_PULSE_WIDTH_192); // 使能ADC ADC14_enableSampleTimer(ADC_MANUAL_MODE); // 使用手动模式 ADC14_enableConversion(); } // 读取心率ADC值 uint16_t read_heart_rate_adc(void) { ADC14_startConversion(); while(ADC14_isBusy()); return ADC14_getResult(ADC_MEM0); } // 将ADC值转换为心率值 (0-16383 -> 30-200 BPM) uint16_t convert_to_heart_rate(uint16_t adc_value) { // 简单线性转换: ADC值映射到30-200 BPM范围 return (adc_value * 170) / 16383 + 30; } // LED闪烁处理函数 void handle_led_blink(void) { static uint32_t last_blink_time = 0; uint32_t current_time = blink_timer; if (current_time - last_blink_time >= 500) { // 500ms闪烁周期 last_blink_time = current_time; led_blink_state = !led_blink_state; if (led_blink_state) { Board_ledOn(LED1 | LED2 | LED3 | LED4 | LED5); } else { Board_ledOff(LED1 | LED2 | LED3 | LED4 | LED5); } } } // 显示心率值 void display_heart_rate(uint16_t rate) { char hr_str[20]; sprintf(hr_str, "Heart Rate: %d", rate); LCD_StringDisplay(20, 50, hr_str); // 显示心率状态 if (rate < NORMAL_LOW_THRESHOLD) { LCD_StringDisplay(20, 80, "Status: LOW"); } else if (rate > NORMAL_HIGH_THRESHOLD) { LCD_StringDisplay(20, 80, "Status: HIGH"); } else { LCD_StringDisplay(20, 80, "Status: NORMAL"); } } #define uchar unsigned char uchar buttonS3_flag; uchar buttonS4_flag; // 瑩攫 #define ROWS 3 #define COLS 4 char keymap[COLS][ROWS] = {{'*', '0', '#'}, {'7', '8', '9'}, {'4', '5', '6'}, {'1', '2', '3'},}; /* Declaring Global Variables */ uint8_t buffer[20]; int k; bool pressed; uint8_t row,col; //LED腑場宎趙 void Board_Led_init(void) { //P9.x output GPIO_setOutputLowOnPin( GPIO_PORT_P9, GPIO_PIN3 | GPIO_PIN4 | GPIO_PIN1 | GPIO_PIN2); GPIO_setAsOutputPin( GPIO_PORT_P9, GPIO_PIN3 | GPIO_PIN4 | GPIO_PIN1 | GPIO_PIN2); //P8.x output GPIO_setOutputLowOnPin( GPIO_PORT_P8, GPIO_PIN7); GPIO_setAsOutputPin( GPIO_PORT_P8, GPIO_PIN7); } void buttoninit(void) { // Button S3 GPIO_setAsInputPin( GPIO_PORT_P2, GPIO_PIN6 ); GPIO_selectInterruptEdge( GPIO_PORT_P2, GPIO_PIN6, GPIO_HIGH_TO_LOW_TRANSITION ); GPIO_enableInterrupt( GPIO_PORT_P2, GPIO_PIN6 ); GPIO_clearInterrupt( GPIO_PORT_P2, GPIO_PIN6 ); // Button S4 GPIO_setAsInputPin( GPIO_PORT_P3, GPIO_PIN1 ); GPIO_selectInterruptEdge( GPIO_PORT_P3, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION ); GPIO_enableInterrupt( GPIO_PORT_P3, GPIO_PIN1 ); GPIO_clearInterrupt( GPIO_PORT_P3, GPIO_PIN1 ); } void Board_ledOn(unsigned char ledMask) { if (ledMask & LED1) GPIO_setOutputHighOnPin(GPIO_PORT_P9, GPIO_PIN3); if (ledMask & LED2) GPIO_setOutputHighOnPin(GPIO_PORT_P9, GPIO_PIN4); if (ledMask & LED3) GPIO_setOutputHighOnPin(GPIO_PORT_P9, GPIO_PIN1); if (ledMask & LED4) GPIO_setOutputHighOnPin(GPIO_PORT_P9, GPIO_PIN2); if (ledMask & LED5) GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN7); } void Board_ledOff(unsigned char ledMask) { if (ledMask & LED1) GPIO_setOutputLowOnPin(GPIO_PORT_P9, GPIO_PIN3); if (ledMask & LED2) GPIO_setOutputLowOnPin(GPIO_PORT_P9, GPIO_PIN4); if (ledMask & LED3) GPIO_setOutputLowOnPin(GPIO_PORT_P9, GPIO_PIN1); if (ledMask & LED4) GPIO_setOutputLowOnPin(GPIO_PORT_P9, GPIO_PIN2); if (ledMask & LED5) GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN7); } void wait_ms(long i) { while(i) { __delay_cycles(20000); i--; blink_timer++; // 更新闪烁计时器 } } void sysclockInit(void) { //Set VCore = 3 for 20MHz clock PMM_setVCore(PMM_CORE_LEVEL_3); //Set DCO FLL reference = REFO UCS_initClockSignal( UCS_FLLREF, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1 ); //Set ACLK = REFO UCS_initClockSignal( UCS_ACLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1 ); //Set Ratio and Desired MCLK Frequency and initialize DCO UCS_initFLLSettle( UCS_MCLK_DESIRED_FREQUENCY_IN_KHZ, UCS_MCLK_FLLREF_RATIO ); // Enable global oscillator fault flag SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT); SFR_enableInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT); // Enable global interrupt __bis_SR_register(GIE); } /* * main.c */ void main(void) { //Stop WDT WDT_A_hold(WDT_A_BASE); sysclockInit(); Board_Led_init(); lcd_init(); LCD_ILI9341_TFT_background(White); LCD_ILI9341_TFT_foreground(Black); // 显示开机界面 LCD_ILI9341_TFT_cls(White); LCD_StringDisplay(60, 100, "Heart Rate Monitor"); LCD_StringDisplay(70, 130, "System Ready"); // LED和数码管全亮 Board_ledOn(LED1 | LED2 | LED3 | LED4 | LED5); Segment_LED_init(); Segment_LED_SHOW(); short_delay(); Segment_LED_Close(); Board_ledOff(LED1 | LED2 | LED3 | LED4 | LED5); // 初始化ADC ADC_init(); // 初始化键盘 I2c_Init(USCI_B1_BASE, GPIO_PORT_P8,GPIO_PIN5, GPIO_PORT_P8,GPIO_PIN6); GPIO_setAsOutputPin(GPIO_PORT_P9,GPIO_PIN5); TCA8418_init(); TCA8418_matrix(ROWS, COLS); TCA8418_flush(); // 初始化按钮 buttonS3_flag = 0; buttonS4_flag = 0; buttoninit(); __bis_SR_register(GIE); while(1) { if (TCA8418_available() > 0) { // 获取键盘事件 k = TCA8418_getEvent(); pressed = k & 0x80; k &= 0x7F; k--; row = k / 10; col = k % 10; } if (pressed) { pressed = false; // 重置按键状态 // 按键1:启动心率监测 if (row == 3 && col == 0) // '1'键 { LCD_ILI9341_TFT_cls(White); LCD_StringDisplay(20, 20, "Heart Rate Monitoring"); heart_rate_display = true; alert_flag = false; Board_ledOff(LED1 | LED2 | LED3 | LED4 | LED5); } // 按键2:清除显示/解除报警 else if (row == 3 && col == 1) // '2'键 { LCD_ILI9341_TFT_cls(White); heart_rate_display = false; alert_flag = false; Board_ledOff(LED1 | LED2 | LED3 | LED4 | LED5); } } // 心率监测模式 if (heart_rate_display) { // 定期采样心率 uint32_t current_time = blink_timer; if (current_time - last_adc_time >= ADC_SAMPLE_INTERVAL) { last_adc_time = current_time; uint16_t adc_value = read_heart_rate_adc(); heart_rate = convert_to_heart_rate(adc_value); display_heart_rate(heart_rate); // 检查心率是否异常 if (heart_rate < NORMAL_LOW_THRESHOLD || heart_rate > NORMAL_HIGH_THRESHOLD) { alert_flag = true; LCD_StringDisplay(20, 110, "ALERT! Abnormal Heart Rate"); } else { alert_flag = false; } } } // 异常报警处理 if (alert_flag) { handle_led_blink(); } // 系统复位按钮(S3) if (buttonS3_flag == 1) { heart_rate_display = false; alert_flag = false; LCD_ILI9341_TFT_background(White); LCD_ILI9341_TFT_foreground(Black); LCD_ILI9341_TFT_cls(White); LCD_StringDisplay(60, 100, "Heart Rate Monitor"); LCD_StringDisplay(70, 130, "System Ready"); Board_ledOff(LED1 | LED2 | LED3 | LED4 | LED5); buttonS3_flag = 0; } // 主循环延时 wait_ms(10); } } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=UNMI_VECTOR __interrupt #elif defined(__GNUC__) __attribute__((interrupt(UNMI_VECTOR))) #endif void NMI_ISR(void) { do { // If it still can't clear the oscillator fault flags after the timeout, // trap and wait here. status = UCS_clearAllOscFlagsWithTimeout(1000); } while(status != 0); } #pragma vector=PORT2_VECTOR __interrupt void PORT2ISR(void) { volatile unsigned int i; for(i = 0; i < 15000; i++); if(!(P2IN & 0x40)) { switch(__even_in_range(P2IV, 16)) { case 0: break; // Vector 0: No interrupt case 2: break; // Vector 2: P2.0 interrupt highest priority case 4: break; // Vector 4: P2.1 interrupt case 6: break; // Vector 6: P2.2 interrupt case 8: break; // Vector 8: P2.3 interrupt case 10: break; // Vector 10: P2.4 interrupt case 12: break; // Vector 12: P2.5 interrupt case 14: buttonS3_flag = 1; buttonS4_flag = 0;// set key pressed flag GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN6); // clear interrupt flag break; // Vector 14: P2.6 interrupt case 16: break; // Vector 16: P2.7 interrupt lowest priority default: break; } } } 报错提示:#141 too many arguments in function call

结合上文的代码判断给出的数据到底是干嘛的#include <ESP8266WiFi.h> #include #include <ArduinoJson.h> #define deviceId "60ee4a31f4b59002868e7677_202soil" #define deviceSecret "123456" /* 连接您的WIFI SSID和密码 */ #define WIFI_SSID "renyang" #define WIFI_PASSWD "renyang123" /* 线上环境域名和端口号,不需要改 */ //华为云地址 #define MQTT_SERVER "25d9de223f.st1.iotda-device.cn-north-4.myhuaweicloud.com" #define MQTT_PORT 1883 #define MQTT_USRNAME "67e23f542902516e866abf9c_speed_1" //硬件的ID和密码 #define CLIENT_ID "67e23f542902516e866abf9c_speed_1_0_0_2025032505" #define MQTT_PASSWD "d41125c3c6587e8cb0179d2d8b12bdd5385f0c3e96e2b0937bd33b9c2a29882c" //硬件发送消息的格式 #define ALINK_BODY_FORMAT "{\"services\":[{\"service_id\":\"soilData\",\"properties\":%s}]}" #define ALINK_TOPIC_PROP_POST "$oc/devices/{"deviceId"/sys/properties/report" #define sensor_Pin 0 //获取土壤数据的引脚 unsigned long lastMs = 0; //用于连接WiFi WiFiClient espClient; //用于连接华为的mqtt服务器 PubSubClient client(espClient); //储存土壤湿度数据 float soil_data = 0; //连接wifi void wifiInit() { WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWD); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("WiFi not Connect"); } Serial.println("WiFi is Connected"); client.setServer(MQTT_SERVER, MQTT_PORT); /* 连接WiFi之后,连接MQTT服务器 */ } //保持mqtt连接 void mqttCheckConnect() { while (!client.connected()) { client.connect(CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD); } } //上报数据到华为云 void mqttIntervalPost() { //获取土壤数据 soil_data = analogRead(sensor_Pin); //模拟数据读取(A0脚输入的数据)385-1024 // soil_data -= 385; //0-639 // soil_data /= 6.39; //0.00-100.00,变为百分比 // soil_data = 100 - soil_data; //修改为百分比越大湿度越大 // char properties[32]; // char jsonBuf[128]; // ////上报数据 // sprintf(properties, "{\"humidity\":%2f}", soil_data); // sprintf(jsonBuf, ALINK_BODY_FORMAT, properties); // b

一、介绍 ESP8266是一款嵌入式系统级芯片,它集成了Wi-Fi功能和微控制器能力于一身,常用于物联网(IoT)项目中。这款芯片支持TCP/IP协议栈,能够连接到WiFi网络,并通过AT命令或者更高级的API与主控设备进行通信。它的低功耗特性使得它可以长时间运行在电池供电下,广泛应用于智能家居、智能门锁、无线传感器网络等应用中。 以下是ESP8266-01S模块的参数: 型号 ESP8266-01S 使用电压 3.0~3.6V WIFI模式 STATION/AP/STATION+AP 通信距离 100M 天线 PCB板载天线 SPI FLASH 1MB 天线标准 802.11B/G/N 哔哩哔哩视频链接: ESP8266模块(WIFI STM32) (资料分享见文末) 二、传感器原理 1.原理图 2.引脚描述 引脚名称 描述 GND GND IO2 通用IO内部已上拉 IO0 工作模式选择 RXD 串口接收 3V3 电源正极3.3V RST 复位 EN 使能 TX 串口发送 3.ESP8266基础AT指令介绍 4.ESP8266基础工作模式 ESP8266WIFI 模式有两种,一种叫 AP 模式,一种叫 Station 模式,AP 就是我们平时所说的热点,如 WIFI 路由器,开了热点的手机,或者是公共热点等,这些 AP 设备可以允许其他设备(如手机,笔记本电脑等)输入热点名和密码(也可不设置密码)后接入,Station 则是前面说的连接 AP 的设备,如:手机,笔记本电脑等,ESP8266 还有第三种模式:AP+Station,即:将 AP 和 Station 的功能合二为一,但是应用的场景不多,这里不做展示。 三、程序设计 使用STM32F103C8T6通过网络调试助手(APP)控制LED亮灭。 ESP8266_TX PA3 ESP8266_RX PA2 LED PA0 串口 串口1 main.c文件 #include "stm32f10x.h" #include "led.h" #include "usart.h" #include "delay.h" #include "esp8266.h" /*****************辰哥单片机设计****************** STM32 * 项目 : ESP8266模块通信实验 * 版本 : V1.0 * 日期 : 2024.9.30 * MCU : STM32F103C8T6 * 接口 : 参看usart2.h * BILIBILI : 辰哥单片机设计 * CSDN : 辰哥单片机设计 * 作者 : 辰哥 **********************BEGIN***********************/ uint8_t flag; int main(void) { SystemInit();//配置系统时钟为72M delay_init(72); LED_Init(); LED_On(); USART_Config(); ESP8266_Init (); //初始化WiFi模块使用的接口和外设(使用串口2) ESP8266_StaTcpClient ();//WiFi模块设置 printf("Start \n"); delay_ms(1000); while (1) { switch(flag) { case 'a': LED_On();break;//开灯 case 'c': LED_Off();break;//关灯 } } } esp8266.h文件 #ifndef __ESP8266_H #define __ESP8266_H #include "stm32f10x.h" #include "common.h" #include <stdio.h> #include <stdbool.h> /*****************辰哥单片机设计****************** STM32 * 项目 : ESP8266模块通信实验 * 版本 : V1.0 * 日期 : 2024.9.30 * MCU : STM32F103C8T6 * 接口 : 串口2 * BILIBILI : 辰哥单片机设计 * CSDN : 辰哥单片机设计 * 作者 : 辰哥 **********************BEGIN***********************/ #if defined ( __CC_ARM ) #pragma anon_unions #endif /******************************* ESP8266 数据类型定义 ***************************/ typedef enum{ STA, AP, STA_AP } ENUM_Net_ModeTypeDef; typedef enum{ enumTCP, enumUDP, } ENUM_NetPro_TypeDef; typedef enum{ Multiple_ID_0 = 0, Multiple_ID_1 = 1, Multiple_ID_2 = 2, Multiple_ID_3 = 3, Multiple_ID_4 = 4, Single_ID_0 = 5, } ENUM_ID_NO_TypeDef; typedef enum{ OPEN = 0, WEP = 1, WPA_PSK = 2, WPA2_PSK = 3, WPA_WPA2_PSK = 4, } ENUM_AP_PsdMode_TypeDef; /******************************* ESP8266 外部全局变量声明 ***************************/ #define RX_BUF_MAX_LEN 1024 //最大接收缓存字节数 extern struct STRUCT_USARTx_Fram //串口数据帧的处理结构体 { char Data_RX_BUF [ RX_BUF_MAX_LEN ]; union { __IO u16 InfAll; struct { __IO u16 FramLength :15; // 14:0 __IO u16 FramFinishFlag :1; // 15 } InfBit; }; } strEsp8266_Fram_Record; /******************************** ESP8266 连接引脚定义 ***********************************/ #define macESP8266_CH_PD_APBxClock_FUN RCC_APB2PeriphClockCmd #define macESP8266_CH_PD_CLK RCC_APB2Periph_GPIOA #define macESP8266_CH_PD_PORT GPIOA #define macESP8266_CH_PD_PIN GPIO_Pin_5 #define macESP8266_RST_APBxClock_FUN RCC_APB2PeriphClockCmd #define macESP8266_RST_CLK RCC_APB2Periph_GPIOA #define macESP8266_RST_PORT GPIOA #define macESP8266_RST_PIN GPIO_Pin_6 #define macESP8266_USART_BAUD_RATE 115200 #define macESP8266_USARTx USART2 #define macESP8266_USART_APBxClock_FUN RCC_APB1PeriphClockCmd #define macESP8266_USART_CLK RCC_APB1Periph_USART2 #define macESP8266_USART_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd #define macESP8266_USART_GPIO_CLK RCC_APB2Periph_GPIOA #define macESP8266_USART_TX_PORT GPIOA #define macESP8266_USART_TX_PIN GPIO_Pin_2 #define macESP8266_USART_RX_PORT GPIOA #define macESP8266_USART_RX_PIN GPIO_Pin_3 #define macESP8266_USART_IRQ USART2_IRQn #define macESP8266_USART_INT_FUN USART2_IRQHandler /*********************************************** ESP8266 函数宏定义 *******************************************/ #define macESP8266_Usart( fmt, ... ) USART_printf ( macESP8266_USARTx, fmt, ##__VA_ARGS__ ) #define macPC_Usart( fmt, ... ) printf ( fmt, ##__VA_ARGS__ ) //#define macPC_Usart( fmt, ... ) #define macESP8266_CH_ENABLE() GPIO_SetBits ( macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN ) #define macESP8266_CH_DISABLE() GPIO_ResetBits ( macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN ) #define macESP8266_RST_HIGH_LEVEL() GPIO_SetBits ( macESP8266_RST_PORT, macESP8266_RST_PIN ) #define macESP8266_RST_LOW_LEVEL() GPIO_ResetBits ( macESP8266_RST_PORT, macESP8266_RST_PIN ) /****************************************** ESP8266 函数声明 ***********************************************/ void ESP8266_Init ( void ); void ESP8266_Rst ( void ); bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime ); void ESP8266_AT_Test ( void ); bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode ); bool ESP8266_JoinAP ( char * pSSID, char * pPassWord ); bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode ); bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx ); bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id); bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver ); uint8_t ESP8266_Get_LinkStatus ( void ); uint8_t ESP8266_Get_IdLinkStatus ( void ); uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength ); bool ESP8266_UnvarnishSend ( void ); void ESP8266_ExitUnvarnishSend ( void ); bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId ); char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx ); /********************************** 用户需要设置的参数**********************************/ #define macUser_ESP8266_ApSsid "www" //要连接的热点的名称 #define macUser_ESP8266_ApPwd "www123456" //要连接的热点的密钥 //#define macUser_ESP8266_TcpServer_IP "192.168.0.11" //要连接的服务器的 IP //#define macUser_ESP8266_TcpServer_Port "8080" //要连接的服务器的端口 /********************************** 外部全局变量 ***************************************/ extern volatile uint8_t ucTcpClosedFlag; /********************************** 测试函数声明 ***************************************/ void ESP8266_StaTcpClient ( void ); #endif /* __ESP8266_H */ esp8266.c文件 #include "esp8266.h" /*****************辰哥单片机设计****************** STM32 * 项目 : ESP8266模块通信实验 * 版本 : V1.0 * 日期 : 2024.9.30 * MCU : STM32F103C8T6 * 接口 : 串口2 * BILIBILI : 辰哥单片机设计 * CSDN : 辰哥单片机设计 * 作者 : 辰哥 **********************BEGIN***********************/ #include "esp8266.h" #include "common.h" #include <stdio.h> #include <string.h> #include <stdbool.h> #include "delay.h" volatile uint8_t ucTcpClosedFlag = 0; char cStr [ 1500 ] = { 0 }; static void ESP8266_GPIO_Config ( void ); static void ESP8266_USART_Config ( void ); static void ESP8266_USART_NVIC_Configuration ( void ); struct STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 }; /** * @brief ESP8266 (Sta Tcp Client)透传 * @param 无 * @retval 无 */ void ESP8266_StaTcpClient ( void ) { // uint8_t ucStatus; // char cStr [ 100 ] = { 0 }; printf ( "\r\n正在配置 ESP8266 ......\r\n" ); macESP8266_CH_ENABLE(); ESP8266_AT_Test (); ESP8266_Net_Mode_Choose ( STA ); while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) ); ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 1000 ); ESP8266_Cmd ( "AT+CIPMUX=1", "OK", 0, 1000 ); ESP8266_Cmd ( "AT+CIPSERVER=1,8288", "OK", 0, 1000 ); //ESP8266_Cmd("AT+CIPSTART="TCP",192.168.1.1,8000","OK",0,1000); printf( "\r\n配置 ESP8266 完毕\r\n" ); } /** * @brief ESP8266初始化函数 * @param 无 * @retval 无 */ void ESP8266_Init ( void ) { // ESP8266_GPIO_Config (); ESP8266_USART_Config (); // macESP8266_RST_HIGH_LEVEL(); // macESP8266_CH_DISABLE(); } /** * @brief 初始化ESP8266用到的GPIO引脚 * @param 无 * @retval 无 */ static void ESP8266_GPIO_Config ( void ) { /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure; /* 配置 CH_PD 引脚*/ macESP8266_CH_PD_APBxClock_FUN ( macESP8266_CH_PD_CLK, ENABLE ); GPIO_InitStructure.GPIO_Pin = macESP8266_CH_PD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init ( macESP8266_CH_PD_PORT, & GPIO_InitStructure ); /* 配置 RST 引脚*/ macESP8266_RST_APBxClock_FUN ( macESP8266_RST_CLK, ENABLE ); GPIO_InitStructure.GPIO_Pin = macESP8266_RST_PIN; GPIO_Init ( macESP8266_RST_PORT, & GPIO_InitStructure ); } /** * @brief 初始化ESP8266用到的 USART * @param 无 * @retval 无 */ static void ESP8266_USART_Config ( void ) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /* config USART clock */ macESP8266_USART_APBxClock_FUN ( macESP8266_USART_CLK, ENABLE ); macESP8266_USART_GPIO_APBxClock_FUN ( macESP8266_USART_GPIO_CLK, ENABLE ); /* USART GPIO config */ /* Configure USART Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = macESP8266_USART_TX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(macESP8266_USART_TX_PORT, &GPIO_InitStructure); /* Configure USART Rx as input floating */ GPIO_InitStructure.GPIO_Pin = macESP8266_USART_RX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(macESP8266_USART_RX_PORT, &GPIO_InitStructure); /* USART1 mode config */ USART_InitStructure.USART_BaudRate = macESP8266_USART_BAUD_RATE; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(macESP8266_USARTx, &USART_InitStructure); /* 中断配置 */ USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断 USART_ITConfig ( macESP8266_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断 ESP8266_USART_NVIC_Configuration (); USART_Cmd(macESP8266_USARTx, ENABLE); } /** * @brief 配置 ESP8266 USART 的 NVIC 中断 * @param 无 * @retval 无 */ static void ESP8266_USART_NVIC_Configuration ( void ) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ NVIC_PriorityGroupConfig ( macNVIC_PriorityGroup_x ); /* Enable the USART2 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = macESP8266_USART_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /* * 函数名:ESP8266_Rst * 描述 :重启WF-ESP8266模块 * 输入 :无 * 返回 : 无 * 调用 :被 ESP8266_AT_Test 调用 */ void ESP8266_Rst ( void ) { #if 0 ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 ); #else macESP8266_RST_LOW_LEVEL(); delay_ms ( 500 ); macESP8266_RST_HIGH_LEVEL(); #endif } /* * 函数名:ESP8266_Cmd * 描述 :对WF-ESP8266模块发送AT指令 * 输入 :cmd,待发送的指令 * reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系 * waittime,等待响应的时间 * 返回 : 1,指令发送成功 * 0,指令发送失败 * 调用 :被外部调用 */ bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime ) { strEsp8266_Fram_Record .InfBit .FramLength = 0; //从新开始接收新的数据包 macESP8266_Usart ( "%s\r\n", cmd ); if ( ( reply1 == 0 ) && ( reply2 == 0 ) ) //不需要接收数据 return true; delay_ms( waittime ); //延时 strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0'; macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF ); if ( ( reply1 != 0 ) && ( reply2 != 0 ) ) return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) || ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) ); else if ( reply1 != 0 ) return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) ); else return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) ); } /* * 函数名:ESP8266_AT_Test * 描述 :对WF-ESP8266模块进行AT测试启动 * 输入 :无 * 返回 : 无 * 调用 :被外部调用 */ void ESP8266_AT_Test ( void ) { char count=0; macESP8266_RST_HIGH_LEVEL(); delay_ms( 1000 ); while ( count < 10 ) { if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) return; ESP8266_Rst(); ++ count; } } /* * 函数名:ESP8266_Net_Mode_Choose * 描述 :选择WF-ESP8266模块的工作模式 * 输入 :enumMode,工作模式 * 返回 : 1,选择成功 * 0,选择失败 * 调用 :被外部调用 */ bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode ) { switch ( enumMode ) { case STA: return ESP8266_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 ); case AP: return ESP8266_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 ); case STA_AP: return ESP8266_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 ); default: return false; } } /* * 函数名:ESP8266_JoinAP * 描述 :WF-ESP8266模块连接外部WiFi * 输入 :pSSID,WiFi名称字符串 * :pPassWord,WiFi密码字符串 * 返回 : 1,连接成功 * 0,连接失败 * 调用 :被外部调用 */ bool ESP8266_JoinAP ( char * pSSID, char * pPassWord ) { char cCmd [120]; sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord ); return ESP8266_Cmd ( cCmd, "OK", NULL, 5000 ); } /* * 函数名:ESP8266_BuildAP * 描述 :WF-ESP8266模块创建WiFi热点 * 输入 :pSSID,WiFi名称字符串 * :pPassWord,WiFi密码字符串 * :enunPsdMode,WiFi加密方式代号字符串 * 返回 : 1,创建成功 * 0,创建失败 * 调用 :被外部调用 */ bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode ) { char cCmd [120]; sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pSSID, pPassWord, enunPsdMode ); return ESP8266_Cmd ( cCmd, "OK", 0, 1000 ); } /* * 函数名:ESP8266_Enable_MultipleId * 描述 :WF-ESP8266模块启动多连接 * 输入 :enumEnUnvarnishTx,配置是否多连接 * 返回 : 1,配置成功 * 0,配置失败 * 调用 :被外部调用 */ bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx ) { return ESP8266_Cmd ( "AT+CIPMUX=%d", "OK", 0, 500 ); } /* * 函数名:ESP8266_Link_Server * 描述 :WF-ESP8266模块连接外部服务器 * 输入 :enumE,网络协议 * :ip,服务器IP字符串 * :ComNum,服务器端口字符串 * :id,模块连接服务器的ID * 返回 : 1,连接成功 * 0,连接失败 * 调用 :被外部调用 */ bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id) { char cStr [100] = { 0 }, cCmd [120]; switch ( enumE ) { case enumTCP: sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum ); break; case enumUDP: sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum ); break; default: break; } if ( id < 5 ) sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr); else sprintf ( cCmd, "AT+CIPSTART=%s", cStr ); return ESP8266_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 ); } /* * 函数名:ESP8266_StartOrShutServer * 描述 :WF-ESP8266模块开启或关闭服务器模式 * 输入 :enumMode,开启/关闭 * :pPortNum,服务器端口号字符串 * :pTimeOver,服务器超时时间字符串,单位:秒 * 返回 : 1,操作成功 * 0,操作失败 * 调用 :被外部调用 */ bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver ) { char cCmd1 [120], cCmd2 [120]; if ( enumMode ) { sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum ); sprintf ( cCmd2, "AT+CIPSTO=%s", pTimeOver ); return ( ESP8266_Cmd ( cCmd1, "OK", 0, 500 ) && ESP8266_Cmd ( cCmd2, "OK", 0, 500 ) ); } else { sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum ); return ESP8266_Cmd ( cCmd1, "OK", 0, 500 ); } } /* * 函数名:ESP8266_Get_LinkStatus * 描述 :获取 WF-ESP8266 的连接状态,较适合单端口时使用 * 输入 :无 * 返回 : 2,获得ip * 3,建立连接 * 3,失去连接 * 0,获取状态失败 * 调用 :被外部调用 */ uint8_t ESP8266_Get_LinkStatus ( void ) { if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) ) { if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:2\r\n" ) ) return 2; else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:3\r\n" ) ) return 3; else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:4\r\n" ) ) return 4; } return 0; } /* * 函数名:ESP8266_Get_IdLinkStatus * 描述 :获取 WF-ESP8266 的端口(Id)连接状态,较适合多端口时使用 * 输入 :无 * 返回 : 端口(Id)的连接状态,低5位为有效位,分别对应Id5~0,某位若置1表该Id建立了连接,若被清0表该Id未建立连接 * 调用 :被外部调用 */ uint8_t ESP8266_Get_IdLinkStatus ( void ) { uint8_t ucIdLinkStatus = 0x00; if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) ) { if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:0," ) ) ucIdLinkStatus |= 0x01; else ucIdLinkStatus &= ~ 0x01; if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:1," ) ) ucIdLinkStatus |= 0x02; else ucIdLinkStatus &= ~ 0x02; if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:2," ) ) ucIdLinkStatus |= 0x04; else ucIdLinkStatus &= ~ 0x04; if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:3," ) ) ucIdLinkStatus |= 0x08; else ucIdLinkStatus &= ~ 0x08; if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:4," ) ) ucIdLinkStatus |= 0x10; else ucIdLinkStatus &= ~ 0x10; } return ucIdLinkStatus; } /* * 函数名:ESP8266_Inquire_ApIp * 描述 :获取 F-ESP8266 的 AP IP * 输入 :pApIp,存放 AP IP 的数组的首地址 * ucArrayLength,存放 AP IP 的数组的长度 * 返回 : 0,获取失败 * 1,获取成功 * 调用 :被外部调用 */ uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength ) { char uc; char * pCh; ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 500 ); pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "APIP,\"" ); if ( pCh ) pCh += 6; else return 0; for ( uc = 0; uc < ucArrayLength; uc ++ ) { pApIp [ uc ] = * ( pCh + uc); if ( pApIp [ uc ] == '\"' ) { pApIp [ uc ] = '\0'; break; } } return 1; } /* * 函数名:ESP8266_UnvarnishSend * 描述 :配置WF-ESP8266模块进入透传发送 * 输入 :无 * 返回 : 1,配置成功 * 0,配置失败 * 调用 :被外部调用 */ //bool ESP8266_UnvarnishSend ( void ) //{ // ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ); //} /* * 函数名:ESP8266_ExitUnvarnishSend * 描述 :配置WF-ESP8266模块退出透传模式 * 输入 :无 * 返回 : 无 * 调用 :被外部调用 */ void ESP8266_ExitUnvarnishSend ( void ) { delay_ms( 1000 ); macESP8266_Usart ( "+++" ); delay_ms( 500 ); } /* * 函数名:ESP8266_SendString * 描述 :WF-ESP8266模块发送字符串 * 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式 * :pStr,要发送的字符串 * :ulStrLength,要发送的字符串的字节数 * :ucId,哪个ID发送的字符串 * 返回 : 1,发送成功 * 0,发送失败 * 调用 :被外部调用 */ bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId ) { char cStr [20]; bool bRet = false; if ( enumEnUnvarnishTx ) { macESP8266_Usart ( "%s", pStr ); bRet = true; } else { if ( ucId < 5 ) sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 ); else sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 ); ESP8266_Cmd ( cStr, "> ", 0, 1000 ); bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 1000 ); } return bRet; } /* * 函数名:ESP8266_ReceiveString * 描述 :WF-ESP8266模块接收字符串 * 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式 * 返回 : 接收到的字符串首地址 * 调用 :被外部调用 */ char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx ) { char * pRecStr = 0; strEsp8266_Fram_Record .InfBit .FramLength = 0; strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0; while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag ); strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0'; if ( enumEnUnvarnishTx ) pRecStr = strEsp8266_Fram_Record .Data_RX_BUF; else { if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" ) ) pRecStr = strEsp8266_Fram_Record .Data_RX_BUF; } return pRecStr; } 对以上内容进行总结和解释,重点说明设计是如何实现的,包括:对设计工作的详细表述。要求层次分明、表达确切。

#include <ESP8266WiFi.h> #include #include <ArduinoJson.h> #define deviceId "60ee4a31f4b59002868e7677_202soil" #define deviceSecret "123456" /* 连接您的WIFI SSID和密码 */ #define WIFI_SSID "renyang" #define WIFI_PASSWD "renyang123" /* 线上环境域名和端口号,不需要改 */ //华为云地址 #define MQTT_SERVER "25d9de223f.st1.iotda-device.cn-north-4.myhuaweicloud.com" #define MQTT_PORT 8883 #define MQTT_USRNAME "67e23f542902516e866abf9c_speed_1" //硬件的ID和密码 #define CLIENT_ID "67e23f542902516e866abf9c_speed_1_0_0_2025032505" #define MQTT_PASSWD "d41125c3c6587e8cb0179d2d8b12bdd5385f0c3e96e2b0937bd33b9c2a29882c" //硬件发送消息的格式 #define ALINK_BODY_FORMAT "{\"services\":[{\"service_id\":\"soilData\",\"properties\":%s}]}" #define ALINK_TOPIC_PROP_POST "$oc/devices/{"deviceId"/sys/properties/report" #define sensor_Pin 0 //获取土壤数据的引脚 unsigned long lastMs = 0; //用于连接WiFi WiFiClient espClient; //用于连接华为的mqtt服务器 PubSubClient client(espClient); //储存土壤湿度数据 float soil_data = 0; //连接wifi void wifiInit() { WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWD); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("WiFi not Connect"); } Serial.println("WiFi is Connected"); client.setServer(MQTT_SERVER, MQTT_PORT); /* 连接WiFi之后,连接MQTT服务器 */ } //保持mqtt连接 void mqttCheckConnect() { while (!client.connected()) { client.connect(CLIENT_ID, MQTT_USRNAME, MQTT_PASSWD); } } //上报数据到华为云 void mqttIntervalPost() { //获取土壤数据 soil_data = analogRead(sensor_Pin); //模拟数据读取(A0脚输入的数据)385-1024 // soil_data -= 385; //0-639 // soil_data /= 6.39; //0.00-100.00,变为百分比 // soil_data = 100 - soil_data; //修改为百分比越大湿度越大 // char properties[32]; // char jsonBuf[128]; // ////上报数据 // sprintf(properties, "{\"humidity\":%2f}", soil_data); // sprintf(jsonBuf, ALINK_BODY_FORMAT, properties); // boolean d = client.pu

最新推荐

recommend-type

掌握XFireSpring整合技术:HELLOworld原代码使用教程

标题:“xfirespring整合使用原代码”中提到的“xfirespring”是指将XFire和Spring框架进行整合使用。XFire是一个基于SOAP的Web服务框架,而Spring是一个轻量级的Java/Java EE全功能栈的应用程序框架。在Web服务开发中,将XFire与Spring整合能够发挥两者的优势,例如Spring的依赖注入、事务管理等特性,与XFire的简洁的Web服务开发模型相结合。 描述:“xfirespring整合使用HELLOworld原代码”说明了在这个整合过程中实现了一个非常基本的Web服务示例,即“HELLOworld”。这通常意味着创建了一个能够返回"HELLO world"字符串作为响应的Web服务方法。这个简单的例子用来展示如何设置环境、编写服务类、定义Web服务接口以及部署和测试整合后的应用程序。 标签:“xfirespring”表明文档、代码示例或者讨论集中于XFire和Spring的整合技术。 文件列表中的“index.jsp”通常是一个Web应用程序的入口点,它可能用于提供一个用户界面,通过这个界面调用Web服务或者展示Web服务的调用结果。“WEB-INF”是Java Web应用中的一个特殊目录,它存放了应用服务器加载的Servlet类文件和相关的配置文件,例如web.xml。web.xml文件中定义了Web应用程序的配置信息,如Servlet映射、初始化参数、安全约束等。“META-INF”目录包含了元数据信息,这些信息通常由部署工具使用,用于描述应用的元数据,如manifest文件,它记录了归档文件中的包信息以及相关的依赖关系。 整合XFire和Spring框架,具体知识点可以分为以下几个部分: 1. XFire框架概述 XFire是一个开源的Web服务框架,它是基于SOAP协议的,提供了一种简化的方式来创建、部署和调用Web服务。XFire支持多种数据绑定,包括XML、JSON和Java数据对象等。开发人员可以使用注解或者基于XML的配置来定义服务接口和服务实现。 2. Spring框架概述 Spring是一个全面的企业应用开发框架,它提供了丰富的功能,包括但不限于依赖注入、面向切面编程(AOP)、数据访问/集成、消息传递、事务管理等。Spring的核心特性是依赖注入,通过依赖注入能够将应用程序的组件解耦合,从而提高应用程序的灵活性和可测试性。 3. XFire和Spring整合的目的 整合这两个框架的目的是为了利用各自的优势。XFire可以用来创建Web服务,而Spring可以管理这些Web服务的生命周期,提供企业级服务,如事务管理、安全性、数据访问等。整合后,开发者可以享受Spring的依赖注入、事务管理等企业级功能,同时利用XFire的简洁的Web服务开发模型。 4. XFire与Spring整合的基本步骤 整合的基本步骤可能包括添加必要的依赖到项目中,配置Spring的applicationContext.xml,以包括XFire特定的bean配置。比如,需要配置XFire的ServiceExporter和ServicePublisher beans,使得Spring可以管理XFire的Web服务。同时,需要定义服务接口以及服务实现类,并通过注解或者XML配置将其关联起来。 5. Web服务实现示例:“HELLOworld” 实现一个Web服务通常涉及到定义服务接口和服务实现类。服务接口定义了服务的方法,而服务实现类则提供了这些方法的具体实现。在XFire和Spring整合的上下文中,“HELLOworld”示例可能包含一个接口定义,比如`HelloWorldService`,和一个实现类`HelloWorldServiceImpl`,该类有一个`sayHello`方法返回"HELLO world"字符串。 6. 部署和测试 部署Web服务时,需要将应用程序打包成WAR文件,并部署到支持Servlet 2.3及以上版本的Web应用服务器上。部署后,可以通过客户端或浏览器测试Web服务的功能,例如通过访问XFire提供的服务描述页面(WSDL)来了解如何调用服务。 7. JSP与Web服务交互 如果在应用程序中使用了JSP页面,那么JSP可以用来作为用户与Web服务交互的界面。例如,JSP可以包含JavaScript代码来发送异步的AJAX请求到Web服务,并展示返回的结果给用户。在这个过程中,JSP页面可能使用XMLHttpRequest对象或者现代的Fetch API与Web服务进行通信。 8. 项目配置文件说明 项目配置文件如web.xml和applicationContext.xml分别在Web应用和服务配置中扮演关键角色。web.xml负责定义Web组件,比如Servlet、过滤器和监听器,而applicationContext.xml则负责定义Spring容器中的bean,包括数据源、事务管理器、业务逻辑组件和服务访问器等。 总之,通过上述整合使用原代码的知识点,可以深入理解XFire与Spring框架的结合使用,以及如何开发和部署基本的Web服务。这些技术知识有助于进行更高层次的Web服务开发,以及在复杂的IT环境中灵活运用各种框架和工具。
recommend-type

【Unity2018汉化大揭秘】:一步到位优化中文用户体验

# 摘要 本论文详细介绍了Unity2018汉化项目的实施过程,从理论准备到实践步骤,再到后期的测试与优化,最终分享了汉化经验和心得。首先,强调了汉化项目对于用户体验提升和产品国际化的重要性,并分析了汉化资源的分类、识别与管理方法。接着,详细阐述了汉化工具的选择、脚本编写、资源手动调整等实践步骤,以及汉化质量测试、体验优化和项目维护更新的重要性。论文最后通过案例研究,分析了汉化中的挑战和应对策略,并预测了汉化技术未来的发展方向。整个汉化过程不仅涉及技术层面的操作,还包含了深入的理论研究和实践心得分享,对提升汉化项目的效率和质量具有指导意义。 # 关键字 Unity汉化;用户体验;国际化;资源
recommend-type

iPhone

<think>我们注意到用户意图不明确,但提到了“照片提取”和“其他功能帮助”。因此,我们需要通过搜索来获取关于iPhone照片提取的常见方法以及其他可能的功能帮助。由于用户问题比较宽泛,我们将重点放在照片提取上,因为这是明确提到的关键词。同时,我们也会考虑一些其他常用功能的帮助。首先,针对照片提取,可能涉及从iPhone导出照片、从备份中提取照片、或者从损坏的设备中恢复照片等。我们将搜索这些方面的信息。其次,关于其他功能帮助,我们可以提供一些常见问题的快速指南,如电池优化、屏幕时间管理等。根据要求,我们需要将答案组织为多个方法或步骤,并在每个步骤间换行。同时,避免使用第一人称和步骤词汇。由于
recommend-type

驾校一点通软件:提升驾驶证考试通过率

标题“驾校一点通”指向的是一款专门为学员考取驾驶证提供帮助的软件,该软件强调其辅助性质,旨在为学员提供便捷的学习方式和复习资料。从描述中可以推断出,“驾校一点通”是一个与驾驶考试相关的应用软件,这类软件一般包含驾驶理论学习、模拟考试、交通法规解释等内容。 文件标题中的“2007”这个年份标签很可能意味着软件的最初发布时间或版本更新年份,这说明了软件具有一定的历史背景和可能经过了多次更新,以适应不断变化的驾驶考试要求。 压缩包子文件的文件名称列表中,有以下几个文件类型值得关注: 1. images.dat:这个文件名表明,这是一个包含图像数据的文件,很可能包含了用于软件界面展示的图片,如各种标志、道路场景等图形。在驾照学习软件中,这类图片通常用于帮助用户认识和记忆不同交通标志、信号灯以及驾驶过程中需要注意的各种道路情况。 2. library.dat:这个文件名暗示它是一个包含了大量信息的库文件,可能包含了法规、驾驶知识、考试题库等数据。这类文件是提供给用户学习驾驶理论知识和准备科目一理论考试的重要资源。 3. 驾校一点通小型汽车专用.exe:这是一个可执行文件,是软件的主要安装程序。根据标题推测,这款软件主要是针对小型汽车驾照考试的学员设计的。通常,小型汽车(C1类驾照)需要学习包括车辆构造、基础驾驶技能、安全行车常识、交通法规等内容。 4. 使用说明.html:这个文件是软件使用说明的文档,通常以网页格式存在,用户可以通过浏览器阅读。使用说明应该会详细介绍软件的安装流程、功能介绍、如何使用软件的各种模块以及如何通过软件来帮助自己更好地准备考试。 综合以上信息,我们可以挖掘出以下几个相关知识点: - 软件类型:辅助学习软件,专门针对驾驶考试设计。 - 应用领域:主要用于帮助驾考学员准备理论和实践考试。 - 文件类型:包括图片文件(images.dat)、库文件(library.dat)、可执行文件(.exe)和网页格式的说明文件(.html)。 - 功能内容:可能包含交通法规知识学习、交通标志识别、驾驶理论学习、模拟考试、考试题库练习等功能。 - 版本信息:软件很可能最早发布于2007年,后续可能有多个版本更新。 - 用户群体:主要面向小型汽车驾照考生,即C1类驾照学员。 - 使用方式:用户需要将.exe安装文件进行安装,然后根据.html格式的使用说明来熟悉软件操作,从而利用images.dat和library.dat中的资源来辅助学习。 以上知识点为从给定文件信息中提炼出来的重点,这些内容对于了解“驾校一点通”这款软件的功能、作用、使用方法以及它的发展历史都有重要的指导意义。
recommend-type

【DFLauncher自动化教程】:简化游戏启动流程,让游戏体验更流畅

# 摘要 DFLauncher是一个功能丰富的游戏启动和管理平台,本论文将介绍其安装、基础使用、高级设置、社区互动以及插件开发等方面。通过对配置文件的解析、界面定制、自动化功能的实现、高级配置选项、安全性和性能监控的详细讨论,本文阐述了DFLauncher如何帮助用户更高效地管理和优化游戏环境。此外,本文还探讨了DFLauncher社区的资源分享、教育教程和插件开发等内容,
recommend-type

自适应卡尔曼滤波是什么意思

<think>嗯,用户这次想深入了解自适应卡尔曼滤波(AKF)的概念和原理。从对话历史看,用户之前研究过相机自动对焦系统的降噪技术,其中提到过自适应卡尔曼滤波的应用场景。用户可能是个工程师或研究者,正在探索信号处理在具体场景的实现细节。 用户提供的三篇参考文献很有价值:[1]是基础理论综述,[2]聚焦多传感器场景,[3]讨论噪声协方差自适应方法。需要特别注意相机AF系统的特殊需求——实时性要求高(每秒数十次对焦计算)、噪声环境复杂(机械振动/弱光干扰),这些在解释原理时要结合具体案例。 技术要点需要分层解析:先明确标准卡尔曼滤波的局限(固定噪声参数),再展开自适应机制。对于相机AF场景,重
recommend-type

EIA-CEA 861B标准深入解析:时间与EDID技术

EIA-CEA 861B标准是美国电子工业联盟(Electronic Industries Alliance, EIA)和消费电子协会(Consumer Electronics Association, CEA)联合制定的一个技术规范,该规范详细规定了视频显示设备和系统之间的通信协议,特别是关于视频显示设备的时间信息(timing)和扩展显示识别数据(Extended Display Identification Data,简称EDID)的结构与内容。 在视频显示技术领域,确保不同品牌、不同型号的显示设备之间能够正确交换信息是至关重要的,而这正是EIA-CEA 861B标准所解决的问题。它为制造商提供了一个统一的标准,以便设备能够互相识别和兼容。该标准对于确保设备能够正确配置分辨率、刷新率等参数至关重要。 ### 知识点详解 #### EIA-CEA 861B标准的历史和重要性 EIA-CEA 861B标准是随着数字视频接口(Digital Visual Interface,DVI)和后来的高带宽数字内容保护(High-bandwidth Digital Content Protection,HDCP)等技术的发展而出现的。该标准之所以重要,是因为它定义了电视、显示器和其他显示设备之间如何交互时间参数和显示能力信息。这有助于避免兼容性问题,并确保消费者能有较好的体验。 #### Timing信息 Timing信息指的是关于视频信号时序的信息,包括分辨率、水平频率、垂直频率、像素时钟频率等。这些参数决定了视频信号的同步性和刷新率。正确配置这些参数对于视频播放的稳定性和清晰度至关重要。EIA-CEA 861B标准规定了多种推荐的视频模式(如VESA标准模式)和特定的时序信息格式,使得设备制造商可以参照这些标准来设计产品。 #### EDID EDID是显示设备向计算机或其他视频源发送的数据结构,包含了关于显示设备能力的信息,如制造商、型号、支持的分辨率列表、支持的视频格式、屏幕尺寸等。这种信息交流机制允许视频源设备能够“了解”连接的显示设备,并自动设置最佳的输出分辨率和刷新率,实现即插即用(plug and play)功能。 EDID的结构包含了一系列的块(block),其中定义了包括基本显示参数、色彩特性、名称和序列号等在内的信息。该标准确保了这些信息能以一种标准的方式被传输和解释,从而简化了显示设置的过程。 #### EIA-CEA 861B标准的应用 EIA-CEA 861B标准不仅适用于DVI接口,还适用于HDMI(High-Definition Multimedia Interface)和DisplayPort等数字视频接口。这些接口技术都必须遵循EDID的通信协议,以保证设备间正确交换信息。由于标准的广泛采用,它已经成为现代视频信号传输和显示设备设计的基础。 #### EIA-CEA 861B标准的更新 随着技术的进步,EIA-CEA 861B标准也在不断地更新和修订。例如,随着4K分辨率和更高刷新率的显示技术的发展,该标准已经扩展以包括支持这些新技术的时序和EDID信息。任何显示设备制造商在设计新产品时,都必须考虑最新的EIA-CEA 861B标准,以确保兼容性。 #### 结论 EIA-CEA 861B标准是电子显示领域的一个重要规范,它详细定义了视频显示设备在通信时所使用的信号时序和设备信息的格式。该标准的存在,使得不同厂商生产的显示设备可以无缝连接和集成,极大地增强了用户体验。对于IT专业人士而言,了解和遵守EIA-CEA 861B标准是进行视频系统设计、故障诊断及设备兼容性测试的重要基础。
recommend-type

【DFLauncher应用实战】:如何将DFLauncher融入矮人要塞并提升效率

# 摘要 DFLauncher是一款功能全面的游戏管理工具,旨在简化游戏安装、启动和维护过程。本文介绍了DFLauncher的基本使用方法,详细解析了其核心功能,包括游戏库管理、游戏配置优化、更新机制等。同时,文章探讨了DFLauncher在特定游戏“矮人要塞”中的集成应用,以及通过插件和脚本进行的高级定制。故障诊断与系统优化章节提供了实用的诊断方法和性能提升技巧。最后,本文展望了DFLauncher的未来发展方向,并鼓励社区贡献和用户反馈,以满足不断变化的用户需求。 # 关键字 DFLauncher;游戏管理工具;安装配置;性能优化;故障诊断;社区贡献;定制化扩展;网络功能集成 参考资源
recommend-type

银河麒麟系统打开屏保

<think>嗯,用户的问题是关于银河麒麟操作系统如何开启屏幕保护程序。这个问题其实挺实用的,毕竟长时间盯着电脑屏幕容易造成视觉疲劳,屏幕保护能起到一定的保护作用。 从用户提供的引用内容来看,引用[2]提到了银河麒麟系统的常见问题处理,包括重启输入法和双屏配置问题,虽然不直接相关,但说明用户对系统设置有一定了解。引用[3]是关于安装cmake的,可能用户之前尝试过其他系统配置操作。 用户可能是在办公环境中使用银河麒麟系统,需要保护视力。考虑到银河麒麟是基于Linux开发的国产操作系统,它的屏幕保护设置应该和主流Linux发行版类似,但可能有自己的特色功能。 我回忆了一下Linux系统的屏
recommend-type

SQL Server 2000官方资料:数据转换与优化

根据提供的文件信息,可以推断出以下知识点: 1. SQL Server 2000官方资料:首先,我们应了解SQL Server 2000是微软发布的一款关系型数据库管理系统,属于SQL Server数据库产品系列的早期版本。官方资料将涵盖此版本的安装、配置、管理以及编程接口等方面的详尽信息。了解SQL Server 2000的官方文档是掌握该软件的基础,对于数据库管理员和开发者来说至关重要。 2. 数据转换:在SQL Server 2000中,数据转换通常涉及将数据从一个格式转换成另一个格式,以便进行进一步的处理或分析。这可能包括使用DTS (Data Transformation Services) 进行数据的导入导出,或是通过编写SQL语句及存储过程来实现复杂的数据清洗和转换逻辑。数据转换的知识点会包括DTS包的设计与执行、各种数据源的连接方法、以及转换过程中的错误处理和日志记录。 3. 数据优化:数据库性能优化是SQL Server 2000的核心知识点之一。数据优化旨在提升数据库的运行效率,包括查询优化、索引管理、存储过程优化等。查询优化可能涉及到使用SQL Server的查询分析器分析查询计划,进而调整SQL语句以提高执行效率。索引管理包括创建、维护和优化索引,而存储过程优化则关注于编写高效的存储过程以减少数据库资源的消耗。 4. 数据备份与恢复:在数据库管理中,数据备份与恢复是保证数据安全性和可靠性的重要措施。SQL Server 2000提供了多种备份选项,例如完整备份、差异备份和日志备份,以及还原数据库的不同策略。管理员需要掌握如何创建备份计划,执行备份操作,同时理解不同备份类型的特点以及在数据丢失或损坏时如何执行恰当的还原操作。 5. 标签信息:"2000官方资料 sqlserver":这个标签强调了文档或文件内容的专一性,指出它专门涉及SQL Server 2000版本。对于IT专业人员来说,理解特定版本的特点和操作是必要的,因为每个版本的数据库管理系统都可能有它独特的功能和限制。因此,此标签提示我们,文中所涉及的技巧、方法和工具都是针对SQL Server 2000的,可能与最新版本有所不同。 6. 压缩包子文件的文件名称列表:虽然提供的列表中只有一个具体的文件名和一个数字,但我们可以推断“中国IT认证实验室学习下载频道.txt”可能是一个包含学习材料下载链接、说明或指南的文本文件。这类文件一般用来提供学习资源信息,可能包含针对SQL Server 2000学习路径的建议,例如官方文档的下载链接、学习书籍的推荐、在线课程介绍等。数字“228”可能是某种编码或文件编号,没有更多的上下文信息,我们难以确定其具体含义。 总结来说,从文件信息中我们可以得知,主要知识点集中在SQL Server 2000的官方资料学习上,具体包括数据转换、数据优化、数据备份与恢复等多个方面。这些内容对于掌握SQL Server 2000的操作和管理至关重要。标签信息进一步指明了内容的专业性和版本特定性,而文件名称列表则可能指向一些学习资源的下载指引。对于数据库管理员和开发者而言,这些知识点的掌握是进行数据库设计、管理和故障排除的基础。