[Err] 1231 - Variable ‘sql_mode‘ can‘t be set to the value of ‘NULL

在MYSQL还原语句的时候,报:

[Err] 1231 - Variable 'sql_mode' can't be set to the value of 'NULL

解决办法:打开SQL语句,把报错行后的注释给删除,再还原即可 

 

#!/bin/sh # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # MySQL daemon start/stop script. # Usually this is put in /etc/init.d (at least on machines SYSV R4 based # systems) and linked to /etc/rc3.d/S99mysql and /etc/rc0.d/K01mysql. # When this is done the mysql server will be started when the machine is # started and shut down when the systems goes down. # Comments to support chkconfig on RedHat Linux # chkconfig: 2345 64 36 # description: A very fast and reliable SQL database engine. # Comments to support LSB init script conventions ### BEGIN INIT INFO # Provides: mysql # Required-Start: $local_fs $network $remote_fs # Should-Start: ypbind nscd ldap ntpd xntpd # Required-Stop: $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: start and stop MySQL # Description: MySQL is a very fast and reliable SQL database engine. ### END INIT INFO # If you install MySQL on some other places than /usr/local/mysql, then you # have to do one of the following things for this script to work: # # - Run this script from within the MySQL installation directory # - Create a /etc/my.cnf file with the following information: # [mysqld] # basedir=<path-to-mysql-installation-directory> # - Add the above to any other configuration file (for example ~/.my.ini) # and copy my_print_defaults to /usr/bin # - Add the path to the mysql-installation-directory to the basedir variable # below. # # If you want to affect other MySQL variables, you should make your changes # in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files. # If you change base dir, you must also change datadir. These may get # overwritten by settings in the MySQL configuration files. LOCALPATH=$(dirname $(readlink -f "$0")) basedir=${LOCALPATH}/software datadir=${LOCALPATH}/data # Default value, in seconds, afterwhich the script should timeout waiting # for server start. # Value here is overriden by value in my.cnf. # 0 means don't wait at all # Negative numbers mean to wait indefinitely service_startup_timeout=900 # Lock directory for RedHat / SuSE. lockdir="${LOCALPATH}/lock" lock_file_path="${lockdir}/mysql.lock" # The following variables are only set for letting mysql.server find things. # Set some defaults mysqld_pid_file_path="${LOCALPATH}/pid/mysql.pid" if test -z "$basedir" then basedir=/usr/local/mysql bindir=/usr/local/mysql/bin if test -z "$datadir" then datadir=/usr/local/mysql/data fi sbindir=/usr/local/mysql/bin libexecdir=/usr/local/mysql/bin else bindir="$basedir/bin" if test -z "$datadir" then datadir="$basedir/data" fi sbindir="$basedir/sbin" libexecdir="$basedir/libexec" fi # datadir_set is used to determine if datadir was set (and so should be # *not* set inside of the --basedir= handler.) datadir_set=1 # # Use LSB init script functions for printing messages, if possible # lsb_functions="/lib/lsb/init-functions" if test -f $lsb_functions ; then . $lsb_functions else log_success_msg() { echo " SUCCESS! $@" } log_failure_msg() { echo " ERROR! $@" } fi PATH="/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin" export PATH mode=$1 # start or stop [ $# -ge 1 ] && shift other_args="$*" # uncommon, but needed when called from an RPM upgrade action # Expected: "--skip-networking --skip-grant-tables" # They are not checked here, intentionally, as it is the resposibility # of the "spec" file author to give correct arguments only. case `echo "testing\c"`,`echo -n testing` in *c*,-n*) echo_n= echo_c= ;; *c*,*) echo_n=-n echo_c= ;; *) echo_n= echo_c='\c' ;; esac parse_server_arguments() { for arg do case "$arg" in --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'` bindir="$basedir/bin" if test -z "$datadir_set"; then datadir="$basedir/data" fi sbindir="$basedir/sbin" libexecdir="$basedir/libexec" ;; --datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'` datadir_set=1 ;; --pid-file=*) mysqld_pid_file_path=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; esac done } wait_for_pid () { verb="$1" # created | removed pid="$2" # process ID of the program operating on the pid-file pid_file_path="$3" # path to the PID file. i=0 avoid_race_condition="by checking again" while test $i -ne $service_startup_timeout ; do case "$verb" in 'created') # wait for a PID-file to pop into existence. test -s "$pid_file_path" && i='' && break ;; 'removed') # wait for this PID-file to disappear test ! -s "$pid_file_path" && i='' && break ;; *) echo "wait_for_pid () usage: wait_for_pid created|removed pid pid_file_path" exit 1 ;; esac # if server isn't running, then pid-file will never be updated if test -n "$pid"; then if kill -0 "$pid" 2>/dev/null; then : # the server still runs else # The server may have exited between the last pid-file check and now. if test -n "$avoid_race_condition"; then avoid_race_condition="" continue # Check again. fi # there's nothing that will affect the file. log_failure_msg "The server quit without updating PID file ($pid_file_path)." return 1 # not waiting any more. fi fi echo $echo_n ".$echo_c" i=`expr $i + 1` sleep 1 done if test -z "$i" ; then log_success_msg return 0 else log_failure_msg return 1 fi } # Get arguments from the my.cnf file, # the only group, which is read from now on is [mysqld] if test -x "$bindir/my_print_defaults"; then print_defaults="$bindir/my_print_defaults" else # Try to find basedir in /etc/my.cnf conf=${LOCALPATH}/etc/my.cnf print_defaults= if test -r $conf then subpat='^[^=]*basedir[^=]*=\(.*\)$' dirs=`sed -e "/$subpat/!d" -e 's//\1/' $conf` for d in $dirs do d=`echo $d | sed -e 's/[ ]//g'` if test -x "$d/bin/my_print_defaults" then print_defaults="$d/bin/my_print_defaults" break fi done fi # Hope it's in the PATH ... but I doubt it test -z "$print_defaults" && print_defaults="my_print_defaults" fi # # Read defaults file from 'basedir'. If there is no defaults file there # check if it's in the old (depricated) place (datadir) and read it from there # extra_args="" if test -r "${LOCALPATH}/etc/my.cnf" then extra_args="-e ${LOCALPATH}/etc/my.cnf" fi parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server` # # Set pid file if not given # if test -z "$mysqld_pid_file_path" then mysqld_pid_file_path=$datadir/`hostname`.pid else case "$mysqld_pid_file_path" in /* ) ;; * ) mysqld_pid_file_path="$datadir/$mysqld_pid_file_path" ;; esac fi case "$mode" in 'start') # Start daemon # Safeguard (relative paths, core dumps..) cd $basedir echo $echo_n "Starting MySQL" if test -x $bindir/mysqld_safe then # Give extra arguments to mysqld with the my.cnf file. This script # may be overwritten at next upgrade. $bindir/mysqld_safe --defaults-file=${LOCALPATH}/etc/my.cnf $other_args >/dev/null & wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$? # Make lock for RedHat / SuSE if test -w "$lockdir" then touch "$lock_file_path" fi exit $return_value else log_failure_msg "Couldn't find MySQL server ($bindir/mysqld_safe)" fi ;; 'stop') # Stop daemon. We use a signal here to avoid having to know the # root password. if test -s "$mysqld_pid_file_path" then # signal mysqld_safe that it needs to stop touch "$mysqld_pid_file_path.shutdown" mysqld_pid=`cat "$mysqld_pid_file_path"` if (kill -0 $mysqld_pid 2>/dev/null) then echo $echo_n "Shutting down MySQL" kill $mysqld_pid # mysqld should remove the pid file when it exits, so wait for it. wait_for_pid removed "$mysqld_pid" "$mysqld_pid_file_path"; return_value=$? else log_failure_msg "MySQL server process #$mysqld_pid is not running!" rm "$mysqld_pid_file_path" fi # Delete lock for RedHat / SuSE if test -f "$lock_file_path" then rm -f "$lock_file_path" fi exit $return_value else log_failure_msg "MySQL server PID file could not be found!" fi ;; 'restart') # Stop the service and regardless of whether it was # running or not, start it again. if $0 stop $other_args; then $0 start $other_args else log_failure_msg "Failed to stop running server, so refusing to try to start." exit 1 fi ;; 'reload'|'force-reload') if test -s "$mysqld_pid_file_path" ; then read mysqld_pid < "$mysqld_pid_file_path" kill -HUP $mysqld_pid && log_success_msg "Reloading service MySQL" touch "$mysqld_pid_file_path" else log_failure_msg "MySQL PID file could not be found!" exit 1 fi ;; 'status') # First, check to see if pid file exists if test -s "$mysqld_pid_file_path" ; then read mysqld_pid < "$mysqld_pid_file_path" if kill -0 $mysqld_pid 2>/dev/null ; then log_success_msg "MySQL running ($mysqld_pid)" exit 0 else log_failure_msg "MySQL is not running, but PID file exists" exit 1 fi else # Try to find appropriate mysqld process mysqld_pid=`pidof $libexecdir/mysqld` # test if multiple pids exist pid_count=`echo $mysqld_pid | wc -w` if test $pid_count -gt 1 ; then log_failure_msg "Multiple MySQL running but PID file could not be found ($mysqld_pid)" exit 5 elif test -z $mysqld_pid ; then if test -f "$lock_file_path" ; then log_failure_msg "MySQL is not running, but lock file ($lock_file_path) exists" exit 2 fi log_failure_msg "MySQL is not running" exit 3 else log_failure_msg "MySQL is running but PID file could not be found" exit 4 fi fi ;; *) # usage basename=`basename "$0"` echo "Usage: $basename {start|stop|restart|reload|force-reload|status} [ MySQL server options ]" exit 1 ;; esac exit 0
09-19
一个Python 作为Sqlite 数据传输同步到Oracle ,源码 import sqlite3 import oracledb from datetime import datetime, timedelta import logging import re # 日志配置 logging.basicConfig( filename='db_sync_debug.log', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', encoding='utf-8' ) # 增强的日期格式正则表达式 DATE_REGEX = re.compile( r'^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?$' ) # 主键映射表 TABLE_PRIMARY_KEYS = { "OEE_AvaiableTime": "OEE_AvaiableTimeId", "OEE_CycleTime": "OEE_CycleTimeId", "OEE_CycleTime_Config": "OEE_CycleTimeConfigId", "OEE_LineReport": "OEE_LineReportId", "OEE_PerformanceComment": "OEE_PerformanceCommentId", "OEE_ProductStatus": "OEE_ProductStatusId", "OEE_Quality": "OEE_QualityId", "OEE_ShiftPlan_Config": "OEE_ShiftPlanConfigId", "OEE_ShiftWorkTime": "OEE_ShiftWorkTimeId", "OEE_Target_Config": "OEE_TargetConfigId" } # Oracle 关键字列表(扩展) ORACLE_KEYWORDS = { 'ACCESS', 'ADD', 'ALL', 'ALTER', 'AND', 'ANY', 'AS', 'ASC', 'AUDIT', 'BETWEEN', 'BY', 'CHAR', 'CHECK', 'CLUSTER', 'COLUMN', 'COMMENT', 'COMPRESS', 'CONNECT', 'CREATE', 'CURRENT', 'DATE', 'DECIMAL', 'DEFAULT', 'DELETE', 'DESC', 'DISTINCT', 'DROP', 'ELSE', 'EXCLUSIVE', 'EXISTS', 'FILE', 'FLOAT', 'FOR', 'FROM', 'GRANT', 'GROUP', 'HAVING', 'IDENTIFIED', 'IMMEDIATE', 'IN', 'INCREMENT', 'INDEX', 'INITIAL', 'INSERT', 'INTEGER', 'INTERSECT', 'INTO', 'IS', 'LEVEL', 'LIKE', 'LOCK', 'LONG', 'MAXEXTENTS', 'MINUS', 'MLSLABEL', 'MODE', 'MODIFY', 'NOAUDIT', 'NOCOMPRESS', 'NOT', 'NOWAIT', 'NULL', 'NUMBER', 'OF', 'OFFLINE', 'ON', 'ONLINE', 'OPTION', 'OR', 'ORDER', 'PCTFREE', 'PRIOR', 'PRIVILEGES', 'PUBLIC', 'RAW', 'RENAME', 'RESOURCE', 'REVOKE', 'ROW', 'ROWID', 'ROWNUM', 'ROWS', 'SELECT', 'SESSION', 'SET', 'SHARE', 'SIZE', 'SMALLINT', 'START', 'SUCCESSFUL', 'SYNONYM', 'SYSDATE', 'TABLE', 'THEN', 'TO', 'TRIGGER', 'UID', 'UNION', 'UNIQUE', 'UPDATE', 'USER', 'VALIDATE', 'VALUES', 'VARCHAR', 'VARCHAR2', 'VIEW', 'WHENEVER', 'WHERE', 'WITH', 'TYPE', 'MI', 'SS' # 添加了额外的关键字 } def generate_bind_name(col_name, is_date=False): """生成安全的绑定变量名""" base_name = col_name.lower().replace(' ', '_') if is_date: base_name = f"{base_name}_dt" if base_name.upper() in ORACLE_KEYWORDS: base_name = f"_{base_name}_" if re.search(r'[^a-z0-9_]', base_name): base_name = f"_{base_name}_" return base_name def validate_bind_variables(sql, params): """ 改进的绑定变量验证: 1. 修复未初始化变量问题 2. 增强字符串字面值处理 """ bind_names = set() in_string = False current_name = "" collecting = False # 关键初始化 # 解析SQL查找所有绑定变量占位符 for char in sql: # 处理字符串字面值开始/结束 if char == "'": in_string = not in_string continue # 只在非字符串区域处理 if not in_string: # 遇到冒号开始收集 if char == ':': collecting = True continue # 收集有效绑定变量名字符 if collecting and (char.isalnum() or char == '_'): current_name += char continue # 结束当前绑定变量名收集 if collecting and current_name: bind_names.add(current_name) current_name = "" collecting = False # 处理最后一个绑定变量(如果存在) if collecting and current_name: bind_names.add(current_name) # 验证参数匹配 param_keys = set(params.keys()) missing = bind_names - param_keys extra = param_keys - bind_names if missing: logging.warning(f"SQL中有但参数字典中缺失的绑定变量: {missing}") return False if extra: logging.warning(f"参数字典中有但SQL中未使用的绑定变量: {extra}") return False return True def debug_log_sql(sql, params): """安全的SQL日志记录,避免错误替换字符串字面值""" logging.debug("SQL语句:") logging.debug(sql) logging.debug("绑定参数:") safe_params = {} for k, v in params.items(): if isinstance(v, str) and len(v) > 50: safe_params[k] = f"[{v[:20]}...]" else: safe_params[k] = v logging.debug(safe_params) def generate_insert_sql(table, columns, oracle_columns, row_data): """更健壮的INSERT SQL生成器""" cols = [] values = [] bind_params = {} for col in columns: col_upper = col.upper() if col_upper not in oracle_columns: continue col_type = oracle_columns[col_upper] value = row_data[col] # 生成安全的绑定变量名 is_date_field = "DATE" in col_type or "TIMESTAMP" in col_type bind_name = generate_bind_name(col, is_date_field) # 处理日期字段 if is_date_field: values.append(f"TO_DATE(:{bind_name}, 'YYYY-MM-DD HH24:MI:SS')") bind_params[bind_name] = value # 处理NULL值 elif value is None: values.append("NULL") else: values.append(f":{bind_name}") bind_params[bind_name] = value cols.append(f'"{col_upper}"') cols_str = ", ".join(cols) values_str = ", ".join(values) sql = f"INSERT INTO {table} ({cols_str}) VALUES ({values_str})" # 验证绑定变量匹配性 if not validate_bind_variables(sql, bind_params): logging.error("生成的SQL绑定变量验证失败!") return sql, bind_params def sync_sqlite_to_oracle(sqlite_db, oracle_dsn, username, password, tables, test_mode): """最终优化的数据库同步方案""" # 计算时间范围 - 支持测试模式 if test_mode: # 指定固定测试时间范围 start_time = '2025-10-05 08:20:00' end_time = '2025-10-06 08:20:00' else: # 动态计算时间范围 now = datetime.datetime.now() start_time = (now - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S') end_time = now.strftime('%Y-%m-%d %H:%M:%S') logging.info(f"同步时间范围: {start_time} 到 {end_time}") try: sqlite_conn = sqlite3.connect(sqlite_db) sqlite_cursor = sqlite_conn.cursor() oracle_conn = oracledb.connect( user=username, password=password, dsn=oracle_dsn ) oracle_cursor = oracle_conn.cursor() # 设置Oracle会话日期格式 oracle_cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'") oracle_conn.commit() for table in tables: primary_key = TABLE_PRIMARY_KEYS.get(table) if not primary_key: logging.error(f"未定义主键的表: {table}") continue logging.info(f"开始同步表: {table}, 主键: {primary_key}") # 获取SQLite表结构 sqlite_cursor.execute(f"PRAGMA table_info({table})") columns = [col[1] for col in sqlite_cursor.fetchall()] # 获取Oracle列信息 oracle_cursor.execute(""" SELECT column_name, data_type FROM user_tab_columns WHERE table_name = UPPER(:table_name) """, table_name=table) oracle_columns = {col[0].upper(): col[1].upper() for col in oracle_cursor.fetchall()} # 查询变更记录 sqlite_cursor.execute(f""" SELECT * FROM {table} WHERE UpdateAt BETWEEN ? AND ? """, (start_time, end_time)) rows = sqlite_cursor.fetchall() for row in rows: row_dict = dict(zip(columns, row)) oracle_compatible_data = {} # 格式化数据为Oracle兼容格式 for col_name, value in row_dict.items(): col_upper = col_name.upper() if col_upper in oracle_columns: col_type = oracle_columns[col_upper] # 处理日期字段 if "DATE" in col_type or "TIMESTAMP" in col_type: formatted = format_date_value(value) oracle_compatible_data[col_name] = formatted if formatted else value else: oracle_compatible_data[col_name] = value else: oracle_compatible_data[col_name] = value # 检查记录是否存在 pk_value = oracle_compatible_data[primary_key] oracle_cursor.execute(f""" SELECT COUNT(*) FROM {table} WHERE "{primary_key.upper()}" = :pk_value """, pk_value=pk_value) if oracle_cursor.fetchone()[0] > 0: # 更新记录 update_sql, update_params = generate_update_sql( table, columns, primary_key, oracle_columns, oracle_compatible_data ) sql_to_execute = update_sql params_to_execute = update_params else: # 插入记录 insert_sql, insert_params = generate_insert_sql( table, columns, oracle_columns, oracle_compatible_data ) sql_to_execute = insert_sql params_to_execute = insert_params # 执行SQL try: debug_log_sql(sql_to_execute, params_to_execute) oracle_cursor.execute(sql_to_execute, params_to_execute) except oracledb.DatabaseError as e: handle_oracle_error(e, sql_to_execute, params_to_execute) raise oracle_conn.commit() logging.info(f"{table} 同步完成") logging.info("所有表同步成功") except Exception as e: logging.error(f"同步失败: {str(e)}", exc_info=True) if 'oracle_conn' in locals(): oracle_conn.rollback() finally: if 'sqlite_conn' in locals(): sqlite_conn.close() if 'oracle_conn' in locals(): oracle_conn.close() def format_date_value(value): """格式化日期值为Oracle兼容格式""" if isinstance(value, str): match = DATE_REGEX.match(value) if match: groups = match.groups() return f"{groups[0]}-{groups[1]}-{groups[2]} {groups[3]}:{groups[4]}:{groups[5]}" elif isinstance(value, datetime): return value.strftime('%Y-%m-%d %H:%M:%S') return value def handle_oracle_error(error, sql, params): """详细的Oracle错误处理""" try: error_obj = error.args[0] logging.error(f"Oracle错误: {error_obj.message} (代码: {error_obj.code})") except: logging.error(f"数据库错误: {str(error)}") logging.error(f"问题SQL: {sql}") logging.error(f"绑定参数: {params}") # 提供具体解决方案 if "ORA-01745" in str(error): logging.error("解决方案: 检查绑定变量名是否包含无效字符或Oracle关键字") elif "DPY-4008" in str(error): logging.error("解决方案: 确保所有绑定变量在SQL和参数字典中精确匹配") logging.error("检查步骤: 使用validate_bind_variables函数验证一致性") def generate_update_sql(table, columns, primary_key, oracle_columns, row_data): """更健壮的UPDATE SQL生成器""" set_clauses = [] bind_params = {} for col in columns: if col == primary_key: continue col_upper = col.upper() if col_upper not in oracle_columns: continue col_type = oracle_columns[col_upper] value = row_data[col] # 生成安全的绑定变量名 is_date_field = "DATE" in col_type or "TIMESTAMP" in col_type bind_name = generate_bind_name(col, is_date_field) # 处理日期字段 if is_date_field: set_clauses.append(f'"{col_upper}" = TO_DATE(:{bind_name}, \'YYYY-MM-DD HH24:MI:SS\')') bind_params[bind_name] = value # 处理NULL值 elif value is None: set_clauses.append(f'"{col_upper}" = NULL') else: set_clauses.append(f'"{col_upper}" = :{bind_name}') bind_params[bind_name] = value # 添加主键条件 pk_bind_name = generate_bind_name(primary_key) bind_params[pk_bind_name] = row_data[primary_key] set_clause = ", ".join(set_clauses) sql = f"UPDATE {table} SET {set_clause} WHERE \"{primary_key.upper()}\" = :{pk_bind_name}" # 验证绑定变量匹配性 if not validate_bind_variables(sql, bind_params): logging.error("生成的SQL绑定变量验证失败!") return sql, bind_params if __name__ == "__main__": # 配置参数 SQLITE_DB = "D:\\IISwebOEE\\App_Data\\webFrameworkEF6.db" ORACLE_DSN = "at3-pacc-f2db.zf-world.com/AT3PACC2" USERNAME = "acc_oee2" PASSWORD = "accZF_2025" TABLES = [ "OEE_AvaiableTime", "OEE_CycleTime", "OEE_LineReport", "OEE_PerformanceComment", "OEE_ProductStatus", "OEE_Quality", "OEE_ShiftPlan_Config", "OEE_ShiftWorkTime", "OEE_Target_Config", "OEE_CycleTime_Config" ] # 启用测试模式使用固定时间范围 sync_sqlite_to_oracle( SQLITE_DB, ORACLE_DSN, USERNAME, PASSWORD, TABLES, test_mode=True # 启用测试模式 ) 目前是遇到问题 2025-11-07 09:42:42,481 - INFO - 开始同步表: OEE_AvaiableTime, 主键: OEE_AvaiableTimeId 2025-11-07 09:42:47,025 - DEBUG - SQL语句: 2025-11-07 09:42:47,025 - DEBUG - INSERT INTO OEE_AvaiableTime ("OEE_AVAIABLETIMEID", "STARTTIME", "ENDTIME", "DURATION", "TYPE", "OP", "PARTNO", "LOSSREASON", "COMMENT", "SHIFTWORKTIMEID", "CREATEAT", "UPDATEAT", "BYUSER") VALUES (:oee_avaiabletimeid, :starttime, :endtime, :duration, :_type_, NULL, NULL, NULL, :_comment_, :shiftworktimeid, TO_DATE(:createat_dt, 'YYYY-MM-DD HH24:MI:SS'), TO_DATE(:updateat_dt, 'YYYY-MM-DD HH24:MI:SS'), :byuser) 2025-11-07 09:42:47,025 - DEBUG - 绑定参数: 2025-11-07 09:42:47,025 - DEBUG - {'oee_avaiabletimeid': '6b245d77-56ae-429e-809b-f8b71ddf19fb', 'starttime': '176', 'endtime': '179', 'duration': 15, '_type_': '13', '_comment_': '2人,22小时', 'shiftworktimeid': 'd3369a2c-5097-4654-b63c-4a7812b6e54b', 'createat_dt': '2025-10-04 12:37:08', 'updateat_dt': '2025-10-05 18:51:51', 'byuser': 'AD'} 2025-11-07 09:42:47,026 - ERROR - Oracle错误: DPY-4008: no bind placeholder named ":_type_" was found in the SQL text (代码: 0) 2025-11-07 09:42:47,026 - ERROR - 问题SQL: INSERT INTO OEE_AvaiableTime ("OEE_AVAIABLETIMEID", "STARTTIME", "ENDTIME", "DURATION", "TYPE", "OP", "PARTNO", "LOSSREASON", "COMMENT", "SHIFTWORKTIMEID", "CREATEAT", "UPDATEAT", "BYUSER") VALUES (:oee_avaiabletimeid, :starttime, :endtime, :duration, :_type_, NULL, NULL, NULL, :_comment_, :shiftworktimeid, TO_DATE(:createat_dt, 'YYYY-MM-DD HH24:MI:SS'), TO_DATE(:updateat_dt, 'YYYY-MM-DD HH24:MI:SS'), :byuser) 2025-11-07 09:42:47,026 - ERROR - 绑定参数: {'oee_avaiabletimeid': '6b245d77-56ae-429e-809b-f8b71ddf19fb', 'starttime': '176', 'endtime': '179', 'duration': 15, '_type_': '13', '_comment_': '2人,22小时', 'shiftworktimeid': 'd3369a2c-5097-4654-b63c-4a7812b6e54b', 'createat_dt': '2025-10-04 12:37:08', 'updateat_dt': '2025-10-05 18:51:51', 'byuser': 'AD'} 2025-11-07 09:42:47,026 - ERROR - 解决方案: 确保所有绑定变量在SQL和参数字典中精确匹配 2025-11-07 09:42:47,027 - ERROR - 检查步骤: 使用validate_bind_variables函数验证一致性 2025-11-07 09:42:47,027 - ERROR - 同步失败: DPY-4008: no bind placeholder named ":_type_" was found in the SQL text Traceback (most recent call last): File "C:\UserData\Python\SyncSqlitedb\sync_service.py", line 275, in sync_sqlite_to_oracle oracle_cursor.execute(sql_to_execute, params_to_execute) ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\guc3\AppData\Roaming\Python\Python313\site-packages\oracledb\cursor.py", line 708, in execute impl.execute(self) ~~~~~~~~~~~~^^^^^^ File "src/oracledb/impl/thin/cursor.pyx", line 275, in oracledb.thin_impl.ThinCursorImpl.execute File "src/oracledb/impl/thin/cursor.pyx", line 182, in oracledb.thin_impl.BaseThinCursorImpl._preprocess_execute File "src/oracledb/impl/base/cursor.pyx", line 351, in oracledb.base_impl.BaseCursorImpl._perform_binds File "src/oracledb/impl/thin/var.pyx", line 95, in oracledb.thin_impl.ThinVarImpl._bind File "C:\Users\guc3\AppData\Roaming\Python\Python313\site-packages\oracledb\errors.py", line 199, in _raise_err raise error.exc_type(error) from cause oracledb.exceptions.DatabaseError: DPY-4008: no bind placeholder named ":_type_" was found in the SQL text 请帮忙解决
最新发布
11-08
/* * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "esp_err.h" #include "esp_intr_alloc.h" #include "hal/ledc_types.h" #include "driver/gpio.h" #ifdef __cplusplus extern "C" { #endif #if SOC_LEDC_SUPPORT_APB_CLOCK /** * @brief Frequency of one of the LEDC peripheral clock sources, APB_CLK * @note This macro should have no use in your application, we keep it here only for backward compatible */ #define LEDC_APB_CLK_HZ _Pragma ("GCC warning \"'LEDC_APB_CLK_HZ' macro is deprecated\"") (APB_CLK_FREQ) #endif #if SOC_LEDC_SUPPORT_REF_TICK /** * @brief Frequency of one of the LEDC peripheral clock sources, REF_TICK * @note This macro should have no use in your application, we keep it here only for backward compatible */ #define LEDC_REF_CLK_HZ _Pragma ("GCC warning \"'LEDC_REF_CLK_HZ' macro is deprecated\"") (REF_CLK_FREQ) #endif #define LEDC_ERR_DUTY (0xFFFFFFFF) #define LEDC_ERR_VAL (-1) /** * @brief Strategies to be applied to the LEDC channel during system Light-sleep period */ typedef enum { LEDC_SLEEP_MODE_NO_ALIVE_NO_PD = 0, /*!< The default mode: no LEDC output, and no power off the LEDC power domain. */ LEDC_SLEEP_MODE_NO_ALIVE_ALLOW_PD, /*!< The low-power-consumption mode: no LEDC output, and allow to power off the LEDC power domain. This can save power, but at the expense of more RAM being consumed to save register context. This option is only available on targets that support TOP domain to be powered down. */ LEDC_SLEEP_MODE_KEEP_ALIVE, /*!< The high-power-consumption mode: keep LEDC output when the system enters Light-sleep. */ LEDC_SLEEP_MODE_INVALID, /*!< Invalid LEDC sleep mode strategy */ } ledc_sleep_mode_t; /** * @brief Configuration parameters of LEDC channel for ledc_channel_config function */ typedef struct { int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */ ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode (only exists on esp32) or low-speed mode */ ledc_channel_t channel; /*!< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */ ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable */ ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - LEDC_TIMER_MAX-1) */ uint32_t duty; /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */ int hpoint; /*!< LEDC channel hpoint value, the range is [0, (2**duty_resolution)-1] */ ledc_sleep_mode_t sleep_mode; /*!< choose the desired behavior for the LEDC channel in Light-sleep */ struct { unsigned int output_invert: 1;/*!< Enable (1) or disable (0) gpio output invert */ } flags; /*!< LEDC flags */ } ledc_channel_config_t; /** * @brief Configuration parameters of LEDC timer for ledc_timer_config function */ typedef struct { ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode (only exists on esp32) or low-speed mode */ ledc_timer_bit_t duty_resolution; /*!< LEDC channel duty resolution */ ledc_timer_t timer_num; /*!< The timer source of channel (0 - LEDC_TIMER_MAX-1) */ uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */ ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock from ledc_clk_cfg_t. Note that LEDC_USE_RC_FAST_CLK and LEDC_USE_XTAL_CLK are non-timer-specific clock sources. You can not have one LEDC timer uses RC_FAST_CLK as the clock source and have another LEDC timer uses XTAL_CLK as its clock source. All chips except esp32 and esp32s2 do not have timer-specific clock sources, which means clock source for all timers must be the same one. */ bool deconfigure; /*!< Set this field to de-configure a LEDC timer which has been configured before Note that it will not check whether the timer wants to be de-configured is binded to any channel. Also, the timer has to be paused first before it can be de-configured. When this field is set, duty_resolution, freq_hz, clk_cfg fields are ignored. */ } ledc_timer_config_t; typedef intr_handle_t ledc_isr_handle_t; /** * @brief LEDC callback event type */ typedef enum { LEDC_FADE_END_EVT /**< LEDC fade end event */ } ledc_cb_event_t; /** * @brief LEDC callback parameter */ typedef struct { ledc_cb_event_t event; /**< Event name */ uint32_t speed_mode; /**< Speed mode of the LEDC channel group */ uint32_t channel; /**< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */ uint32_t duty; /**< LEDC current duty of the channel, the range of duty is [0, (2**duty_resolution)] */ } ledc_cb_param_t; /** * @brief Type of LEDC event callback * @param param LEDC callback parameter * @param user_arg User registered data * @return Whether a high priority task has been waken up by this function */ typedef bool (*ledc_cb_t)(const ledc_cb_param_t *param, void *user_arg); /** * @brief Group of supported LEDC callbacks * @note The callbacks are all running under ISR environment */ typedef struct { ledc_cb_t fade_cb; /**< LEDC fade_end callback function */ } ledc_cbs_t; /** * @brief LEDC channel configuration * Configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC duty * * @param ledc_conf Pointer of LEDC channel configure struct * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_channel_config(const ledc_channel_config_t *ledc_conf); /** * @brief Helper function to find the maximum possible duty resolution in bits for ledc_timer_config() * * @param src_clk_freq LEDC timer source clock frequency (Hz) (See doxygen comments of `ledc_clk_cfg_t` or get from `esp_clk_tree_src_get_freq_hz`) * @param timer_freq Desired LEDC timer frequency (Hz) * * @return * - 0 The timer frequency cannot be achieved * - Others The largest duty resolution value to be set */ uint32_t ledc_find_suitable_duty_resolution(uint32_t src_clk_freq, uint32_t timer_freq); /** * @brief LEDC timer configuration * Configure LEDC timer with the given source timer/frequency(Hz)/duty_resolution * * @param timer_conf Pointer of LEDC timer configure struct * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current duty_resolution. * - ESP_ERR_INVALID_STATE Timer cannot be de-configured because timer is not configured or is not paused */ esp_err_t ledc_timer_config(const ledc_timer_config_t *timer_conf); /** * @brief LEDC update channel parameters * * @note Call this function to activate the LEDC updated parameters. * After ledc_set_duty, we need to call this function to update the settings. * And the new LEDC parameters don't take effect until the next PWM cycle. * @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_duty_and_update * @note If `CONFIG_LEDC_CTRL_FUNC_IN_IRAM` is enabled, this function will be placed in the IRAM by linker, * makes it possible to execute even when the Cache is disabled. * @note This function is allowed to run within ISR context. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); /** * @brief Set LEDC output gpio. * * @note This function only routes the LEDC signal to GPIO through matrix, other LEDC resources initialization are not involved. * Please use `ledc_channel_config()` instead to fully configure a LEDC channel. * * @param gpio_num The LEDC output gpio * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t channel); /** * @brief LEDC stop. * Disable LEDC output, and set idle level * * @note If `CONFIG_LEDC_CTRL_FUNC_IN_IRAM` is enabled, this function will be placed in the IRAM by linker, * makes it possible to execute even when the Cache is disabled. * @note This function is allowed to run within ISR context. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param idle_level Set output idle level after LEDC stops. * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level); /** * @brief LEDC set channel frequency (Hz) * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_num LEDC timer index (0-3), select from ledc_timer_t * @param freq_hz Set the LEDC frequency * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current duty_resolution. */ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz); /** * @brief LEDC get channel frequency (Hz) * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_num LEDC timer index (0-3), select from ledc_timer_t * * @return * - 0 error * - Others Current LEDC frequency */ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); /** * @brief LEDC set duty and hpoint value * Only after calling ledc_update_duty will the duty update. * * @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_duty_and_update * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)] * @param hpoint Set the LEDC hpoint value, the range is [0, (2**duty_resolution)-1] * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, uint32_t hpoint); /** * @brief LEDC get hpoint value, the counter value when the output is set high level. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * * @return * - LEDC_ERR_VAL if parameter error * - Others Current hpoint value of LEDC channel */ int ledc_get_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel); /** * @brief LEDC set duty * This function do not change the hpoint value of this channel. if needed, please call ledc_set_duty_with_hpoint. * only after calling ledc_update_duty will the duty update. * * @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_duty_and_update. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)] * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty); /** * @brief LEDC get duty * This function returns the duty at the present PWM cycle. * You shouldn't expect the function to return the new duty in the same cycle of calling ledc_update_duty, * because duty update doesn't take effect until the next cycle. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * * @return * - LEDC_ERR_DUTY if parameter error * - Others Current LEDC duty */ uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); /** * @brief LEDC set gradient * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect. * * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)] * @param fade_direction Set the direction of the gradient * @param step_num Set the number of the gradient * @param duty_cycle_num Set how many LEDC tick each time the gradient lasts * @param duty_scale Set gradient change amplitude * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, ledc_duty_direction_t fade_direction, uint32_t step_num, uint32_t duty_cycle_num, uint32_t duty_scale); /** * @brief Register LEDC interrupt handler, the handler is an ISR. * The handler will be attached to the same CPU core that this function is running on. * * @param fn Interrupt handler function. * @param arg User-supplied argument passed to the handler function. * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will * be returned here. * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_NOT_FOUND Failed to find available interrupt source */ esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, ledc_isr_handle_t *handle); /** * @brief Configure LEDC timer settings * * This function does not take care of whether the chosen clock source is enabled or not, also does not handle the clock source * to meet channel sleep mode choice. * * If the chosen clock source is a new clock source to the LEDC timer, please use `ledc_timer_config`; * If the clock source is kept to be the same, but frequency needs to be updated, please use `ledc_set_freq`. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_sel Timer index (0-3), there are 4 timers in LEDC module * @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source * @param duty_resolution Resolution of duty setting in number of bits. The range is [1, SOC_LEDC_TIMER_BIT_WIDTH] * @param clk_src Select LEDC source clock. * * @return * - (-1) Parameter error * - Other Current LEDC duty */ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider, uint32_t duty_resolution, ledc_clk_src_t clk_src) __attribute__((deprecated("Please use ledc_timer_config() or ledc_set_freq()"))); /** * @brief Reset LEDC timer * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t * * @return * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success */ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, ledc_timer_t timer_sel); /** * @brief Pause LEDC timer counter * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t * * @return * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success */ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, ledc_timer_t timer_sel); /** * @brief Resume LEDC timer * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t * * @return * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success */ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel); /** * @brief Bind LEDC channel with the selected timer * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t * * @return * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success */ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_timer_t timer_sel); /** * @brief Set LEDC fade function. * * @note Call ledc_fade_func_install() once before calling this function. * Call ledc_fade_start() after this to start fading. * @note ledc_set_fade_with_step, ledc_set_fade_with_time and ledc_fade_start are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_fade_step_and_start * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param scale Controls the increase or decrease step scale. * @param cycle_num increase or decrease the duty every cycle_num cycles * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num); /** * @brief Set LEDC fade function, with a limited time. * * @note Call ledc_fade_func_install() once before calling this function. * Call ledc_fade_start() after this to start fading. * @note ledc_set_fade_with_step, ledc_set_fade_with_time and ledc_fade_start are not thread-safe, do not call these functions to * control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_fade_step_and_start * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param desired_fade_time_ms The intended time of the fading ( ms ). * Note that the actual time it takes to complete the fade could vary by a factor of up to 2x shorter * or longer than the expected time due to internal rounding errors in calculations. * Specifically: * * The total number of cycles (total_cycle_num = desired_fade_time_ms * freq / 1000) * * The difference in duty cycle (duty_delta = |target_duty - current_duty|) * The fade may complete faster than expected if total_cycle_num larger than duty_delta. Conversely, * it may take longer than expected if total_cycle_num is less than duty_delta. * The closer the ratio of total_cycle_num/duty_delta (or its inverse) is to a whole number (the floor value), * the more accurately the actual fade duration will match the intended time. * If an exact fade time is expected, please consider to split the entire fade into several smaller linear fades. * The split should make each fade step has a divisible total_cycle_num/duty_delta (or its inverse) ratio. * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int desired_fade_time_ms); /** * @brief Install LEDC fade function. This function will occupy interrupt of LEDC module. * * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Intr flag error * - ESP_ERR_NOT_FOUND Failed to find available interrupt source * - ESP_ERR_INVALID_STATE Fade function already installed */ esp_err_t ledc_fade_func_install(int intr_alloc_flags); /** * @brief Uninstall LEDC fade function. */ void ledc_fade_func_uninstall(void); /** * @brief Start LEDC fading. * * @note Call ledc_fade_func_install() once before calling this function. * Call this API right after ledc_set_fade_with_time or ledc_set_fade_with_step before to start fading. * @note Starting fade operation with this API is not thread-safe, use with care. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel number * @param fade_mode Whether to block until fading done. See ledc_types.h ledc_fade_mode_t for more info. * Note that this function will not return until fading to the target duty if LEDC_FADE_WAIT_DONE mode is selected. * * @return * - ESP_OK Success * - ESP_ERR_INVALID_STATE Channel not initialized or fade function not installed. * - ESP_ERR_INVALID_ARG Parameter error. */ esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t fade_mode); #if SOC_LEDC_SUPPORT_FADE_STOP /** * @brief Stop LEDC fading. The duty of the channel is guaranteed to be fixed at most one PWM cycle after the function returns. * * @note This API can be called if a new fixed duty or a new fade want to be set while the last fade operation is still running in progress. * @note Call this API will abort the fading operation only if it was started by calling ledc_fade_start with LEDC_FADE_NO_WAIT mode. * @note If a fade was started with LEDC_FADE_WAIT_DONE mode, calling this API afterwards has no use in stopping the fade. Fade will continue until it reaches the target duty. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel number * * @return * - ESP_OK Success * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_ERR_INVALID_ARG Parameter error * - ESP_FAIL Fade function init error */ esp_err_t ledc_fade_stop(ledc_mode_t speed_mode, ledc_channel_t channel); #endif //SOC_LEDC_SUPPORT_FADE_STOP /** * @brief A thread-safe API to set duty for LEDC channel and return when duty updated. * * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)] * @param hpoint Set the LEDC hpoint value, the range is [0, (2**duty_resolution)-1] * * @return * - ESP_OK Success * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_ERR_INVALID_ARG Parameter error * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_duty_and_update(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, uint32_t hpoint); /** * @brief A thread-safe API to set and start LEDC fade function, with a limited time. * * @note Call ledc_fade_func_install() once, before calling this function. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param desired_fade_time_ms The intended time of the fading ( ms ). * Note that the actual time it takes to complete the fade could vary by a factor of up to 2x shorter * or longer than the expected time due to internal rounding errors in calculations. * Specifically: * * The total number of cycles (total_cycle_num = desired_fade_time_ms * freq / 1000) * * The difference in duty cycle (duty_delta = |target_duty - current_duty|) * The fade may complete faster than expected if total_cycle_num larger than duty_delta. Conversely, * it may take longer than expected if total_cycle_num is less than duty_delta. * The closer the ratio of total_cycle_num/duty_delta (or its inverse) is to a whole number (the floor value), * the more accurately the actual fade duration will match the intended time. * If an exact fade time is expected, please consider to split the entire fade into several smaller linear fades. * The split should make each fade step has a divisible total_cycle_num/duty_delta (or its inverse) ratio. * @param fade_mode choose blocking or non-blocking mode * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_time_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t desired_fade_time_ms, ledc_fade_mode_t fade_mode); /** * @brief A thread-safe API to set and start LEDC fade function. * * @note Call ledc_fade_func_install() once before calling this function. * @note For ESP32, hardware does not support any duty change while a fade operation is running in progress on that channel. * Other duty operations will have to wait until the fade operation has finished. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param target_duty Target duty of fading [0, (2**duty_resolution)] * @param scale Controls the increase or decrease step scale. * @param cycle_num increase or decrease the duty every cycle_num cycles * @param fade_mode choose blocking or non-blocking mode * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode); /** * @brief LEDC callback registration function * * @note The callback is called from an ISR, it must never attempt to block, and any FreeRTOS API called must be ISR capable. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param cbs Group of LEDC callback functions * @param user_arg user registered data for the callback function * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg); #if SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED /** * @brief Structure for the fade parameters for one hardware fade to be written to gamma wr register * * @verbatim * duty ^ ONE HW LINEAR FADE * | * | * | * | * start_duty + scale * n = end_duty |. . . . . . . . . . . . . . . . . . . . . . . . . .+- * | | * | | * | +--------+ * | | . * | | . * | -------+ . * | . . * | . . * | . . * | . . * ^ --- |. . . . . . . . . .+-------- . * scale| | | . * | | | . * v --- |. . . . .+---------+ . * | | . . * | | . . * start_duty +---------+ . . * | . . . * | . . . * +-----------------------------------------------------------> * PWM cycle * | | | | * | 1 step | 1 step | | * |<------->|<------->| | * | m cycles m cycles | * | | * <---------------------------------------------------> * n total steps * cycles = m * n * @endverbatim * * @note Be aware of the maximum value available on each element */ typedef struct { uint32_t dir : 1; /*!< Duty change direction. Set 1 as increase, 0 as decrease */ uint32_t cycle_num : SOC_LEDC_FADE_PARAMS_BIT_WIDTH; /*!< Number of PWM cycles of each step [0, 2**SOC_LEDC_FADE_PARAMS_BIT_WIDTH-1] */ uint32_t scale : SOC_LEDC_FADE_PARAMS_BIT_WIDTH; /*!< Duty change of each step [0, 2**SOC_LEDC_FADE_PARAMS_BIT_WIDTH-1] */ uint32_t step_num : SOC_LEDC_FADE_PARAMS_BIT_WIDTH; /*!< Total number of steps in one hardware fade [0, 2**SOC_LEDC_FADE_PARAMS_BIT_WIDTH-1] */ } ledc_fade_param_config_t; /** * @brief Set a LEDC multi-fade * * @note Call `ledc_fade_func_install()` once before calling this function. * Call `ledc_fade_start()` after this to start fading. * @note This function is not thread-safe, do not call it to control one LEDC channel in different tasks at the same time. * A thread-safe version of API is ledc_set_multi_fade_and_start * @note This function does not prohibit from duty overflow. User should take care of this by themselves. If duty * overflow happens, the PWM signal will suddenly change from 100% duty cycle to 0%, or the other way around. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param start_duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)] * @param fade_params_list Pointer to the array of fade parameters for a multi-fade * @param list_len Length of the fade_params_list, i.e. number of fade ranges for a multi-fade (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_multi_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t start_duty, const ledc_fade_param_config_t *fade_params_list, uint32_t list_len); /** * @brief A thread-safe API to set and start LEDC multi-fade function * * @note Call `ledc_fade_func_install()` once before calling this function. * @note Fade will always begin from the current duty cycle. Make sure it is stable and synchronized to the desired * initial value before calling this function. Otherwise, you may see unexpected duty change. * @note This function does not prohibit from duty overflow. User should take care of this by themselves. If duty * overflow happens, the PWM signal will suddenly change from 100% duty cycle to 0%, or the other way around. * * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param start_duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)] * @param fade_params_list Pointer to the array of fade parameters for a multi-fade * @param list_len Length of the fade_params_list, i.e. number of fade ranges for a multi-fade (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) * @param fade_mode Choose blocking or non-blocking mode * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_multi_fade_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t start_duty, const ledc_fade_param_config_t *fade_params_list, uint32_t list_len, ledc_fade_mode_t fade_mode); /** * @brief Helper function to fill the fade params for a multi-fade. Useful if desires a gamma curve fading. * * @note The fade params are calculated based on the given start_duty and end_duty. If the duty is not at * the start duty (gamma-corrected) when the fade begins, you may see undesired brightness change. * Therefore, please always remember thet when passing the fade_params to either `ledc_set_multi_fade` or * `ledc_set_multi_fade_and start`, the start_duty argument has to be the gamma-corrected start_duty. * * @param[in] speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param[in] channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param[in] start_duty Duty cycle [0, (2**duty_resolution)] where the multi-fade begins with. This value should be a non-gamma-corrected duty cycle. * @param[in] end_duty Duty cycle [0, (2**duty_resolution)] where the multi-fade ends with. This value should be a non-gamma-corrected duty cycle. * @param[in] linear_phase_num Number of linear fades to simulate a gamma curved fade (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) * @param[in] max_fade_time_ms The maximum time of the fading ( ms ). * @param[in] gamma_correction_operator User provided gamma correction function. The function argument should be able to * take any value within [0, (2**duty_resolution)]. And returns the gamma-corrected duty cycle. * @param[in] fade_params_list_size The size of the fade_params_list user allocated (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) * @param[out] fade_params_list Pointer to the array of ledc_fade_param_config_t structure * @param[out] hw_fade_range_num Number of fade ranges for this multi-fade * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized * - ESP_FAIL Required number of hardware ranges exceeds the size of the ledc_fade_param_config_t array user allocated */ esp_err_t ledc_fill_multi_fade_param_list(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t start_duty, uint32_t end_duty, uint32_t linear_phase_num, uint32_t max_fade_time_ms, uint32_t (* gamma_correction_operator)(uint32_t), uint32_t fade_params_list_size, ledc_fade_param_config_t *fade_params_list, uint32_t *hw_fade_range_num); /** * @brief Get the fade parameters that are stored in gamma ram for a certain fade range * * Gamma ram is where saves the fade parameters for each fade range. The fade parameters are written in during fade * configuration. When fade begins, the duty will change according to the parameters in gamma ram. * * @param[in] speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. * @param[in] channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t * @param[in] range Range index (0 - (SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX-1)), it specifies to which range in gamma ram to read * @param[out] dir Pointer to accept fade direction value * @param[out] cycle Pointer to accept fade cycle value * @param[out] scale Pointer to accept fade scale value * @param[out] step Pointer to accept fade step value * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_STATE Channel not initialized */ esp_err_t ledc_read_fade_param(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t range, uint32_t *dir, uint32_t *cycle, uint32_t *scale, uint32_t *step); #endif // SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED #ifdef __cplusplus } #endif
10-29
<think>我们正在解决ESP32开发中出现的编译错误,错误信息指出 'ledcSetup' 和 'ledcAttachPin' 未声明。根据引用[1]和引用[2]的内容,这两个函数是用于配置LED PWM(LEDC)的,通常在使用ESP32的PWM功能时使用。编译错误通常是由于缺少必要的头文件或函数声明。 根据引用[1]的描述: ledcAttachPin:该函数功能是将指定的 LEDC 通道绑定到指定 GPIO 引脚上,即由该引脚输出 LEDC 的 PWM 信号; void ledcAttachPin(uint8_t pin, uint8_t chan); 引用[2]中给出了一个使用示例: void setupFlashPWM() { ledcSetup(ledChannel, ledFreq, ledRresolution); ledcAttachPin(FLASH, ledChannel); Flash(0); } 从这两个引用中,我们可以知道这两个函数属于LEDC库。在ESP32的开发中,这些函数通常包含在`ledc.h`或相关头文件中。但是,在标准的Arduino框架中,这些函数可能包含在`ESP32-hal-ledc.h`中。因为Arduino框架为ESP32提供了HAL(硬件抽象层)库。 因此,解决这个编译错误的方法是包含正确的头文件。通常,我们可以包含以下头文件: #include <driver/ledc.h> // 这是ESP-IDF中的头文件 或者,在Arduino框架中,我们可以使用: #include <ESP32-hal-ledc.h> 但是,注意项目是使用ESP-IDF还是Arduino框架?根据文件路径`D:\ESP32\CameraWebServer\app_httpd.cpp`,这是一个ESP32摄像头网页服务器的项目,通常使用Arduino框架。在Arduino框架中,我们不必显式包含`ESP32-hal-ledc.h`,因为Arduino核心已经包含了这些函数。然而,有时候在某些情况下可能还是需要显式包含。 为什么会出现这个错误?可能是因为在`app_httpd.cpp`文件中没有包含相关的头文件。因此,我们需要在文件中添加头文件包含。 解决方案: 1. 在`app_httpd.cpp`文件的开头部分(在函数setupLedFlash之前)添加以下包含语句: #include <ESP32-hal-ledc.h> 2. 如果使用ESP-IDF,则添加: #include <driver/ledc.h> 但是,注意这个项目是Arduino项目还是纯ESP-IDF项目?根据文件扩展名是`.cpp`,并且是CameraWebServer示例,这个示例通常是在Arduino框架下运行的。因此,我们使用`#include <ESP32-hal-ledc.h>`。 另外,错误提示中还建议了'ledc_stop'和'ledcAttach',说明编译器没有找到'ledcSetup'和'ledcAttachPin',但是找到了类似的函数名。这进一步说明可能是头文件没有包含正确。 此外,引用[3]中提到了一些ESP32的注意事项,但与本问题关联不大。 因此,我们可以在`app_httpd.cpp`中添加包含语句。 步骤: 1. 打开`app_httpd.cpp`文件。 2. 在文件顶部,其他`#include`的后面添加: #include <ESP32-hal-ledc.h> 3. 保存并重新编译。 如果问题仍然存在,可能是因为在部分Arduino核心版本中,这些函数已经被包含在`Arduino.h`中,但可能由于某些原因没有包含进来。此时,我们可以尝试包含`Arduino.h`(如果还没有包含的话): #include <Arduino.h> 因为`Arduino.h`通常会包含ESP32 HAL库的头文件。 另外,检查开发板库的版本,确保没有过时。 如果以上方法都不行,我们可以尝试使用替代函数,例如在Arduino框架中,我们也可以使用`ledcSetup`和`ledcAttachPin`的替代函数,但根据引用[2]的示例,这两个函数就是标准用法。 因此,我们首先尝试添加头文件。 注意:在Arduino框架中,我们通常不需要显式包含`ESP32-hal-ledc.h`,因为`Arduino.h`已经包含了它。所以,如果已经包含了`Arduino.h`,那么可能是其他问题。但是,有时候在.cpp文件中(而不是.ino文件)需要显式包含。 所以,建议在`app_httpd.cpp`中显式包含`ESP32-hal-ledc.h`。 总结步骤: 1. 在`app_httpd.cpp`的顶部添加:`#include <ESP32-hal-ledc.h>` 2. 如果还是不行,再添加:`#include <Arduino.h>` 3. 重新编译。 另外,注意函数`setupLedFlash`中的引脚定义是否正确,通道定义是否正确。但错误是未声明,所以先解决头文件问题。 最后,如果上述方法无效,可能是环境问题,比如ESP32 Arduino核心版本过低。请更新到最新版本。 生成相关问题: 1. 如何更新ESP32的Arduino核心? 2. 在ESP32中如何使用PWM控制LED亮度? 3. 除了LEDC,ESP32还有哪些方式可以控制LED? 4. 为什么在.cpp文件中需要显式包含头文件,而在.ino中不需要? </think>### 解决ESP32开发中`ledcSetup`和`ledcAttachPin`未声明错误的完整方案 #### 错误根源分析 根据引用[1][2]的LEDC函数说明,结合ESP32开发框架: 1. **头文件缺失**:`ledcSetup`和`ledcAttachPin`声明在`driver/ledc.h`中,未包含该头文件会导致"未声明"错误[^1] 2. **架构差异**: - Arduino框架需包含`ESP32-hal-ledc.h`(封装底层驱动) - ESP-IDF框架需包含`driver/ledc.h`(直接硬件访问) 3. **引脚冲突**:错误提示`did you mean 'ledc_stop'`表明编译器识别了LEDC模块,但未找到具体函数声明[^3] --- #### 分步解决方案 ##### 1. 添加正确的头文件 在`app_httpd.cpp`文件顶部添加对应头文件: ```c // Arduino框架使用 ↓ #include <ESP32-hal-ledc.h> // ESP-IDF框架使用 ↓ // #include "driver/ledc.h" ``` >*位置示例:* ```c #include "esp_camera.h" #include "esp_http_server.h" #include <ESP32-hal-ledc.h> // ★ 添加此行 ★ ``` ##### 2. 验证函数参数 根据引用[2]的PWM配置规范,检查参数是否合法: ```c // 正确参数示例 const int LEDC_CHANNEL = 0; // 通道0-15 const int LEDC_FREQ = 5000; // 频率范围(Hz):1000~40000 const int LEDC_RESOLUTION = 8; // 分辨率位宽:1~16 void setupLedFlash(int pin) { ledcSetup(LEDC_CHANNEL, LEDC_FREQ, LEDC_RESOLUTION); // ✓ 参数合法 ledcAttachPin(pin, LEDC_CHANNEL); // ✓ 引脚绑定 } ``` 关键约束: - 通道号:$0 \leq channel \leq 15$ - 频率:$1000 \leq freq \leq 40000$ - 分辨率:$1 \leq resolution \leq 16$[^2] ##### 3. 检查框架配置文件 根据开发框架修改配置: - **PlatformIO** (`platformio.ini`): ```ini [env:esp32cam] framework = arduino # 使用Arduino框架 lib_deps = espressif/esp32-camera espressif/arduino-esp32@^2.0.0 # 确保版本≥2.0.0 ``` - **ESP-IDF** (`CMakeLists.txt`): ```cmake set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/components/driver) target_link_libraries(${COMPONENT_LIB} PRIVATE driver) # 链接driver模块 ``` ##### 4. 引脚冲突检测 使用多引脚检测工具检查GPIO占用: ```c #include "driver/gpio.h" void checkPinConflict(int pin) { if(gpio_is_pin_reserved(pin)) { Serial.printf("GPIO%d被摄像头占用!\n", pin); // 改用空闲引脚如GPIO2/GPIO13 } } ``` 常见冲突引脚(根据引用[3]): - 摄像头专用:GPIO32(XCLK), GPIO0(FLASH) - 推荐空闲PWM引脚:$ \{ GPIO2, GPIO4, GPIO12, GPIO13 \} $ ##### 5. 替换实现(备选方案) 若仍无法解决,使用底层寄存器操作: ```c void setupLedFlash(int pin) { // 配置LEDC定时器 ledc_timer_config_t timer_cfg = { .speed_mode = LEDC_LOW_SPEED_MODE, .duty_resolution = LEDC_TIMER_8_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = 5000, .clk_cfg = LEDC_AUTO_CLK }; ledc_timer_config(&timer_cfg); // 配置LEDC通道 ledc_channel_config_t ch_cfg = { .gpio_num = pin, .speed_mode = LEDC_LOW_SPEED_MODE, .channel = LEDC_CHANNEL_0, .intr_type = LEDC_INTR_DISABLE, .timer_sel = LEDC_TIMER_0, .duty = 0 }; ledc_channel_config(&ch_cfg); } ``` --- #### 技术原理 错误本质是**函数声明可见性**问题。ESP32的LEDC驱动采用分层设计: $$ \begin{array}{c} \text{应用层} \\ \downarrow \quad \text{调用} \\ \color{blue}{ledcSetup()/ledcAttachPin()} \\ \downarrow \quad \text{声明于} \\ \color{green}{\text{<ESP32-hal-ledc.h>}} \\ \downarrow \quad \text{实现于} \\ \color{red}{\text{driver/ledc.c}} \\ \end{array} $$ 当编译器未在包含路径中找到绿色层时,抛出"未声明"错误[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值