This commit is contained in:
2026-05-21 08:07:16 +08:00
parent 90908cf018
commit 84d8874a38
32 changed files with 271 additions and 27 deletions
+23
View File
@@ -32,6 +32,7 @@ static AttendanceRecord attendance_records[MAX_ATTENDANCE_RECORDS];
static uint16_t record_count = 0; static uint16_t record_count = 0;
static uint32_t total_attendance_count = 0; // 总考勤人次 static uint32_t total_attendance_count = 0; // 总考勤人次
/* 函数作用:根据当前小时和分钟查找所处的考勤时间段。 */
static int8_t Attendance_FindTimeSlot(uint8_t hour, uint8_t minute) static int8_t Attendance_FindTimeSlot(uint8_t hour, uint8_t minute)
{ {
uint16_t current_minutes = hour * 60 + minute; uint16_t current_minutes = hour * 60 + minute;
@@ -57,6 +58,7 @@ static int8_t Attendance_FindTimeSlot(uint8_t hour, uint8_t minute)
/** /**
* @brief 初始化考勤模块 * @brief 初始化考勤模块
*/ */
/* 函数作用:初始化考勤记录、时间段配置和今日已签到缓存。 */
void Attendance_Init(void) void Attendance_Init(void)
{ {
record_count = 0; record_count = 0;
@@ -81,6 +83,7 @@ void Attendance_Init(void)
/** /**
* @brief 清空今日签到缓存 * @brief 清空今日签到缓存
*/ */
/* 函数作用:清空当前时段的服务器已签到学号缓存。 */
void Attendance_ClearCache(void) void Attendance_ClearCache(void)
{ {
cached_id_count = 0; cached_id_count = 0;
@@ -93,6 +96,7 @@ void Attendance_ClearCache(void)
/** /**
* @brief 添加学号到缓存 * @brief 添加学号到缓存
*/ */
/* 函数作用:把指定学号加入当前考勤时段的本地查重缓存。 */
void Attendance_AddToCache(const char* student_id) void Attendance_AddToCache(const char* student_id)
{ {
int8_t current_slot = Attendance_GetCurrentTimeSlot(); int8_t current_slot = Attendance_GetCurrentTimeSlot();
@@ -132,6 +136,7 @@ void Attendance_AddToCache(const char* student_id)
* @brief 在本地缓存中查重 * @brief 在本地缓存中查重
* @retval 1=在缓存中找到(重复), 0=未找到 * @retval 1=在缓存中找到(重复), 0=未找到
*/ */
/* 函数作用:检查指定学号是否已存在于当前时段缓存中。 */
uint8_t Attendance_IsDuplicateInCache(const char* student_id) uint8_t Attendance_IsDuplicateInCache(const char* student_id)
{ {
int8_t current_slot = Attendance_GetCurrentTimeSlot(); int8_t current_slot = Attendance_GetCurrentTimeSlot();
@@ -158,6 +163,7 @@ uint8_t Attendance_IsDuplicateInCache(const char* student_id)
* @brief 从服务器加载今日已签到记录到缓存 * @brief 从服务器加载今日已签到记录到缓存
* @retval 加载的记录数量 * @retval 加载的记录数量
*/ */
/* 函数作用:下载当前时段已签到学号列表并写入本地查重缓存。 */
uint8_t Attendance_LoadTodayRecordsFromServer(void) uint8_t Attendance_LoadTodayRecordsFromServer(void)
{ {
char slot_start[8]; char slot_start[8];
@@ -221,6 +227,7 @@ uint8_t Attendance_LoadTodayRecordsFromServer(void)
* @param slots 新的时间段配置数组 * @param slots 新的时间段配置数组
* @param count 时间段数量 * @param count 时间段数量
*/ */
/* 函数作用:用服务端下发的新时间段数组替换本地时间段配置。 */
void Attendance_UpdateTimeSlots(TimeSlot* slots, uint8_t count) void Attendance_UpdateTimeSlots(TimeSlot* slots, uint8_t count)
{ {
if (count > MAX_TIME_SLOT_COUNT) { if (count > MAX_TIME_SLOT_COUNT) {
@@ -249,6 +256,7 @@ void Attendance_UpdateTimeSlots(TimeSlot* slots, uint8_t count)
* @param json_str JSON字符串(格式:{"time_slots":[{"enabled":true,"start_time":"08:00",...}]}) * @param json_str JSON字符串(格式:{"time_slots":[{"enabled":true,"start_time":"08:00",...}]})
* @retval 成功解析的时间段数量 * @retval 成功解析的时间段数量
*/ */
/* 函数作用:从服务端同步 JSON 中解析时间段配置并应用到本地。 */
uint8_t Attendance_ParseTimeSlotsJSON(const char* json_str) uint8_t Attendance_ParseTimeSlotsJSON(const char* json_str)
{ {
TimeSlot temp_slots[MAX_TIME_SLOT_COUNT]; TimeSlot temp_slots[MAX_TIME_SLOT_COUNT];
@@ -386,6 +394,7 @@ uint8_t Attendance_ParseTimeSlotsJSON(const char* json_str)
* @param hour 小时 (0-23) * @param hour 小时 (0-23)
* @param minute 分钟 (0-59) * @param minute 分钟 (0-59)
*/ */
/* 函数作用:更新考勤模块当前时间,并在跨时段时清空查重缓存。 */
void Attendance_SetCurrentTime(uint8_t hour, uint8_t minute) void Attendance_SetCurrentTime(uint8_t hour, uint8_t minute)
{ {
int8_t old_slot = Attendance_FindTimeSlot(current_hour, current_minute); int8_t old_slot = Attendance_FindTimeSlot(current_hour, current_minute);
@@ -405,6 +414,7 @@ void Attendance_SetCurrentTime(uint8_t hour, uint8_t minute)
* @brief 获取当前所处的考勤时段 * @brief 获取当前所处的考勤时段
* @retval 时段编号 (0-N),如果不在任何时段内则返回 -1 * @retval 时段编号 (0-N),如果不在任何时段内则返回 -1
*/ */
/* 函数作用:返回当前时间对应的考勤时段索引。 */
int8_t Attendance_GetCurrentTimeSlot(void) int8_t Attendance_GetCurrentTimeSlot(void)
{ {
return Attendance_FindTimeSlot(current_hour, current_minute); return Attendance_FindTimeSlot(current_hour, current_minute);
@@ -415,6 +425,7 @@ int8_t Attendance_GetCurrentTimeSlot(void)
* @param start_time 输出:开始时间(格式"HH:MM") * @param start_time 输出:开始时间(格式"HH:MM")
* @param end_time 输出:结束时间(格式"HH:MM") * @param end_time 输出:结束时间(格式"HH:MM")
*/ */
/* 函数作用:输出当前考勤时段的开始和结束时间字符串。 */
void Attendance_GetCurrentSlotTime(char* start_time, char* end_time) void Attendance_GetCurrentSlotTime(char* start_time, char* end_time)
{ {
int8_t current_slot = Attendance_GetCurrentTimeSlot(); int8_t current_slot = Attendance_GetCurrentTimeSlot();
@@ -438,6 +449,7 @@ void Attendance_GetCurrentSlotTime(char* start_time, char* end_time)
* @param student_id 学生学号 * @param student_id 学生学号
* @retval 1=服务器显示已签到(重复), 0=未签到或查询失败 * @retval 1=服务器显示已签到(重复), 0=未签到或查询失败
*/ */
/* 函数作用:向服务器查询指定学生在当前时段是否已经签到。 */
uint8_t Attendance_IsDuplicateOnServer(const char* student_id) uint8_t Attendance_IsDuplicateOnServer(const char* student_id)
{ {
char slot_start[8]; char slot_start[8];
@@ -458,6 +470,7 @@ uint8_t Attendance_IsDuplicateOnServer(const char* student_id)
* @param student_id 学生学号 * @param student_id 学生学号
* @retval 1=重复, 0=不重复 * @retval 1=重复, 0=不重复
*/ */
/* 函数作用:检查指定学生是否已在当前时段产生本地重复签到。 */
uint8_t Attendance_IsDuplicate(const char* student_id) uint8_t Attendance_IsDuplicate(const char* student_id)
{ {
int8_t current_slot = Attendance_GetCurrentTimeSlot(); int8_t current_slot = Attendance_GetCurrentTimeSlot();
@@ -485,6 +498,7 @@ uint8_t Attendance_IsDuplicate(const char* student_id)
* @param result 人脸识别结果 * @param result 人脸识别结果
* @retval 考勤状态 * @retval 考勤状态
*/ */
/* 函数作用:校验识别结果、查重并生成一条待同步考勤记录。 */
AttendanceStatus Attendance_ProcessFaceResult(FaceRecognitionResult* result) AttendanceStatus Attendance_ProcessFaceResult(FaceRecognitionResult* result)
{ {
// 1. 检查识别是否成功 // 1. 检查识别是否成功
@@ -598,6 +612,7 @@ AttendanceStatus Attendance_ProcessFaceResult(FaceRecognitionResult* result)
/** /**
* @brief 清空所有考勤记录 * @brief 清空所有考勤记录
*/ */
/* 函数作用:清空当前缓存的考勤记录,但保留累计统计值。 */
void Attendance_ClearRecords(void) void Attendance_ClearRecords(void)
{ {
record_count = 0; record_count = 0;
@@ -608,6 +623,7 @@ void Attendance_ClearRecords(void)
/** /**
* @brief 获取累计考勤总数 * @brief 获取累计考勤总数
*/ */
/* 函数作用:返回系统启动以来累计处理的成功考勤次数。 */
uint16_t Attendance_GetTotalCount(void) uint16_t Attendance_GetTotalCount(void)
{ {
return total_attendance_count; return total_attendance_count;
@@ -616,6 +632,7 @@ uint16_t Attendance_GetTotalCount(void)
/** /**
* @brief 获取当前缓存中的记录数 * @brief 获取当前缓存中的记录数
*/ */
/* 函数作用:返回当前本地缓存中的考勤记录数量。 */
uint16_t Attendance_GetActiveCount(void) uint16_t Attendance_GetActiveCount(void)
{ {
return record_count; return record_count;
@@ -625,6 +642,7 @@ uint16_t Attendance_GetActiveCount(void)
* @brief 获取待同步记录的数量(PENDING或FAILED状态) * @brief 获取待同步记录的数量(PENDING或FAILED状态)
* @retval 待同步记录数 * @retval 待同步记录数
*/ */
/* 函数作用:统计当前等待上传或需要重试上传的记录数量。 */
uint16_t Attendance_GetPendingCount(void) uint16_t Attendance_GetPendingCount(void)
{ {
uint16_t count = 0; uint16_t count = 0;
@@ -644,6 +662,7 @@ uint16_t Attendance_GetPendingCount(void)
* @param index 输出参数,返回记录的索引 * @param index 输出参数,返回记录的索引
* @retval 记录指针,如果没有待同步记录则返回NULL * @retval 记录指针,如果没有待同步记录则返回NULL
*/ */
/* 函数作用:按优先级取出下一条可上传或可重试的考勤记录。 */
AttendanceRecord* Attendance_GetNextPendingRecord(uint16_t* index) AttendanceRecord* Attendance_GetNextPendingRecord(uint16_t* index)
{ {
uint32_t current_time = Get_Time_ms(); uint32_t current_time = Get_Time_ms();
@@ -690,6 +709,7 @@ AttendanceRecord* Attendance_GetNextPendingRecord(uint16_t* index)
* @param index 记录索引 * @param index 记录索引
* @param status 新的同步状态 * @param status 新的同步状态
*/ */
/* 函数作用:更新指定考勤记录的服务器同步状态。 */
void Attendance_MarkSyncStatus(uint16_t index, SyncStatus status) void Attendance_MarkSyncStatus(uint16_t index, SyncStatus status)
{ {
if (index < record_count) if (index < record_count)
@@ -711,6 +731,7 @@ void Attendance_MarkSyncStatus(uint16_t index, SyncStatus status)
* @brief 增加记录的重试计数 * @brief 增加记录的重试计数
* @param index 记录索引 * @param index 记录索引
*/ */
/* 函数作用:增加指定记录的上传重试次数。 */
void Attendance_IncrementRetry(uint16_t index) void Attendance_IncrementRetry(uint16_t index)
{ {
if (index < record_count) if (index < record_count)
@@ -724,6 +745,7 @@ void Attendance_IncrementRetry(uint16_t index)
/** /**
* @brief 将所有FAILED记录重置为PENDING(用于网络恢复后) * @brief 将所有FAILED记录重置为PENDING(用于网络恢复后)
*/ */
/* 函数作用:网络恢复后把失败记录重新置为待同步状态。 */
void Attendance_ResetFailedRecords(void) void Attendance_ResetFailedRecords(void)
{ {
uint16_t reset_count = 0; uint16_t reset_count = 0;
@@ -748,6 +770,7 @@ void Attendance_ResetFailedRecords(void)
* @param index 记录索引 * @param index 记录索引
* @retval 记录指针,如果索引无效则返回NULL * @retval 记录指针,如果索引无效则返回NULL
*/ */
/* 函数作用:根据数组索引返回对应考勤记录指针。 */
AttendanceRecord* Attendance_GetRecordByIndex(uint16_t index) AttendanceRecord* Attendance_GetRecordByIndex(uint16_t index)
{ {
if (index < record_count) if (index < record_count)
+40 -18
View File
@@ -51,29 +51,51 @@ typedef struct {
} TimeSlot; } TimeSlot;
// 函数声明 // 函数声明
// 函数作用:初始化考勤模块的记录缓存、时间段配置和运行状态。
void Attendance_Init(void); void Attendance_Init(void);
void Attendance_SetCurrentTime(uint8_t hour, uint8_t minute); // 设置当前时间 // 函数作用:设置考勤模块当前使用的小时和分钟,用于判断当前是否处于考勤时段。
void Attendance_UpdateTimeSlots(TimeSlot* slots, uint8_t count); // 更新时间段配置(从服务器下载后调用) void Attendance_SetCurrentTime(uint8_t hour, uint8_t minute);
uint8_t Attendance_ParseTimeSlotsJSON(const char* json_str); // 从JSON字符串解析时间段配置 // 函数作用:使用服务器下发的时间段数组更新本地考勤时间段配置。
void Attendance_UpdateTimeSlots(TimeSlot* slots, uint8_t count);
// 函数作用:从服务器返回的 JSON 字符串中解析时间段配置并更新本地列表。
uint8_t Attendance_ParseTimeSlotsJSON(const char* json_str);
// 函数作用:处理 K210 人脸识别结果,判断是否可打卡并生成考勤记录。
AttendanceStatus Attendance_ProcessFaceResult(FaceRecognitionResult* result); AttendanceStatus Attendance_ProcessFaceResult(FaceRecognitionResult* result);
// 函数作用:检查指定学号在当前考勤时段内是否已经打卡。
uint8_t Attendance_IsDuplicate(const char* student_id); uint8_t Attendance_IsDuplicate(const char* student_id);
uint8_t Attendance_IsDuplicateOnServer(const char* student_id); // 服务器端查重 // 函数作用:通过服务器接口检查指定学号在当前时段是否已经打卡。
void Attendance_GetCurrentSlotTime(char* start_time, char* end_time); // 获取当前时段时间 uint8_t Attendance_IsDuplicateOnServer(const char* student_id);
uint8_t Attendance_LoadTodayRecordsFromServer(void); // 新增:从服务器加载今日签到记录 // 函数作用:获取当前考勤时段的开始和结束时间字符串。
uint8_t Attendance_IsDuplicateInCache(const char* student_id); // 新增:在本地缓存中查重 void Attendance_GetCurrentSlotTime(char* start_time, char* end_time);
void Attendance_AddToCache(const char* student_id); // 新增:添加学号到缓存 // 函数作用:从服务器加载今日已签到记录,用于设备重启后恢复去重缓存。
void Attendance_ClearCache(void); // 新增:清空缓存 uint8_t Attendance_LoadTodayRecordsFromServer(void);
// 函数作用:在本地今日签到缓存中检查指定学号是否已存在。
uint8_t Attendance_IsDuplicateInCache(const char* student_id);
// 函数作用:把指定学号加入本地今日签到缓存。
void Attendance_AddToCache(const char* student_id);
// 函数作用:清空本地今日签到缓存。
void Attendance_ClearCache(void);
// 函数作用:清空本地保存的考勤记录和同步状态。
void Attendance_ClearRecords(void); void Attendance_ClearRecords(void);
uint16_t Attendance_GetTotalCount(void); // 获取累计考勤总数 // 函数作用:返回累计考勤记录总数。
uint16_t Attendance_GetActiveCount(void); // 获取当前缓存记录数 uint16_t Attendance_GetTotalCount(void);
int8_t Attendance_GetCurrentTimeSlot(void); // 获取当前时段编号(-1表示不在考勤时段) // 函数作用:返回当前本地缓存中的有效记录数量。
uint16_t Attendance_GetActiveCount(void);
// 函数作用:返回当前所在考勤时段编号,-1 表示不在任意考勤时段。
int8_t Attendance_GetCurrentTimeSlot(void);
// 数据同步相关函数 // 数据同步相关函数
uint16_t Attendance_GetPendingCount(void); // 获取待同步记录数量(PENDING状态) // 函数作用:统计当前处于待同步状态的考勤记录数量。
AttendanceRecord* Attendance_GetNextPendingRecord(uint16_t* index); // 获取下一个待同步记录 uint16_t Attendance_GetPendingCount(void);
void Attendance_MarkSyncStatus(uint16_t index, SyncStatus status); // 更新记录的同步状态 // 函数作用:查找下一条待同步记录,并通过 index 返回其在缓存中的位置。
void Attendance_IncrementRetry(uint16_t index); // 增加重试计数 AttendanceRecord* Attendance_GetNextPendingRecord(uint16_t* index);
AttendanceRecord* Attendance_GetRecordByIndex(uint16_t index); // 按索引获取记录 // 函数作用:按缓存索引更新指定考勤记录的同步状态。
void Attendance_ResetFailedRecords(void); // 将所有FAILED记录重置为PENDING void Attendance_MarkSyncStatus(uint16_t index, SyncStatus status);
// 函数作用:按缓存索引增加指定考勤记录的同步重试次数。
void Attendance_IncrementRetry(uint16_t index);
// 函数作用:按缓存索引返回指定考勤记录指针。
AttendanceRecord* Attendance_GetRecordByIndex(uint16_t index);
// 函数作用:将所有同步失败记录重置为待同步,便于后续重新上传。
void Attendance_ResetFailedRecords(void);
#endif #endif
+1
View File
@@ -1,5 +1,6 @@
#include "Buzzer_LED.h" #include "Buzzer_LED.h"
/* 函数作用:初始化蜂鸣器、成功指示灯和板载状态 LED 对应 GPIO。 */
void Buzzer_LED_Init(void) void Buzzer_LED_Init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
+1
View File
@@ -14,6 +14,7 @@
#define LED_STATUS_OFF() GPIO_SetBits(GPIOC, GPIO_Pin_13) // 就绪后:熄灭 #define LED_STATUS_OFF() GPIO_SetBits(GPIOC, GPIO_Pin_13) // 就绪后:熄灭
// 声明初始化函数 // 声明初始化函数
// 函数作用:初始化成功指示灯、状态灯和蜂鸣器相关 GPIO 输出状态。
void Buzzer_LED_Init(void); void Buzzer_LED_Init(void);
#endif #endif
+5
View File
@@ -23,6 +23,7 @@ static const uint8_t AES_IV[16] = {
static struct AES_ctx aes_ctx; static struct AES_ctx aes_ctx;
/* 函数作用:初始化 AES 加密上下文。 */
void Crypto_Init(void) void Crypto_Init(void)
{ {
// 初始化AES上下文(使用CBC模式) // 初始化AES上下文(使用CBC模式)
@@ -33,6 +34,7 @@ void Crypto_Init(void)
* @brief PKCS#7填充 * @brief PKCS#7填充
* 将数据填充到16字节的倍数 * 将数据填充到16字节的倍数
*/ */
/* 函数作用:为 JSON 明文追加 PKCS#7 填充。 */
static uint32_t pkcs7_pad(uint8_t* data, uint32_t data_len, uint32_t buffer_size) static uint32_t pkcs7_pad(uint8_t* data, uint32_t data_len, uint32_t buffer_size)
{ {
// 计算需要填充的字节数 // 计算需要填充的字节数
@@ -52,6 +54,7 @@ static uint32_t pkcs7_pad(uint8_t* data, uint32_t data_len, uint32_t buffer_size
return data_len + padding_len; return data_len + padding_len;
} }
/* 函数作用:移除解密结果中的 PKCS#7 填充。 */
static uint32_t pkcs7_unpad(uint8_t* data, uint32_t data_len) static uint32_t pkcs7_unpad(uint8_t* data, uint32_t data_len)
{ {
uint8_t padding_len; uint8_t padding_len;
@@ -75,6 +78,7 @@ static uint32_t pkcs7_unpad(uint8_t* data, uint32_t data_len)
return data_len - padding_len; return data_len - padding_len;
} }
/* 函数作用:将 JSON 字符串 AES-CBC 加密并 Base64 编码输出。 */
uint32_t Crypto_EncryptJSON(const char* json_data, char* encrypted_output) uint32_t Crypto_EncryptJSON(const char* json_data, char* encrypted_output)
{ {
uint32_t json_len = strlen(json_data); uint32_t json_len = strlen(json_data);
@@ -121,6 +125,7 @@ uint32_t Crypto_EncryptJSON(const char* json_data, char* encrypted_output)
return encoded_len; return encoded_len;
} }
/* 函数作用:将 Base64 密文解码并 AES-CBC 解密为 JSON 字符串。 */
uint32_t Crypto_DecryptJSON(const char* encrypted_base64, char* plain_output, uint32_t output_size) uint32_t Crypto_DecryptJSON(const char* encrypted_base64, char* plain_output, uint32_t output_size)
{ {
uint32_t encrypted_len; uint32_t encrypted_len;
+3
View File
@@ -12,6 +12,7 @@
* *
* 注意:encrypted_output缓冲区至少需要 (strlen(json_data) / 16 + 1) * 16 * 4/3 + 10 字节 * 注意:encrypted_output缓冲区至少需要 (strlen(json_data) / 16 + 1) * 16 * 4/3 + 10 字节
*/ */
// 函数作用:对 JSON 字符串执行 AES-CBC 加密和 Base64 编码,生成可上传服务端的密文。
uint32_t Crypto_EncryptJSON(const char* json_data, char* encrypted_output); uint32_t Crypto_EncryptJSON(const char* json_data, char* encrypted_output);
/** /**
@@ -21,6 +22,7 @@ uint32_t Crypto_EncryptJSON(const char* json_data, char* encrypted_output);
* @param output_size 输出缓冲区大小 * @param output_size 输出缓冲区大小
* @return 明文字节数,失败返回0 * @return 明文字节数,失败返回0
*/ */
// 函数作用:对 Base64 编码的 AES-CBC 密文进行解码和解密,输出 JSON 明文。
uint32_t Crypto_DecryptJSON(const char* encrypted_base64, char* plain_output, uint32_t output_size); uint32_t Crypto_DecryptJSON(const char* encrypted_base64, char* plain_output, uint32_t output_size);
/** /**
@@ -34,6 +36,7 @@ uint32_t Crypto_DecryptJSON(const char* encrypted_base64, char* plain_output, ui
* @brief 初始化加密模块 * @brief 初始化加密模块
* 设置密钥和IV(初始化向量) * 设置密钥和IV(初始化向量)
*/ */
// 函数作用:初始化加密模块使用的固定密钥、IV 和底层 AES 上下文。
void Crypto_Init(void); void Crypto_Init(void);
#endif // _CRYPTO_H_ #endif // _CRYPTO_H_
+9
View File
@@ -33,6 +33,7 @@
#define DEC_TO_BCD(dec) ((((dec) / 10) << 4) | ((dec) % 10)) #define DEC_TO_BCD(dec) ((((dec) / 10) << 4) | ((dec) % 10))
// 微秒延时 // 微秒延时
/* 函数作用:为 DS1302 时序提供简短的微秒级软件延时。 */
static void delay_us(uint32_t us) static void delay_us(uint32_t us)
{ {
volatile uint32_t i; volatile uint32_t i;
@@ -44,6 +45,7 @@ static void delay_us(uint32_t us)
/** /**
* @brief 配置IO口为输出 * @brief 配置IO口为输出
*/ */
/* 函数作用:把 DS1302 数据引脚配置为推挽输出模式。 */
static void DS1302_DATAOUT_init(void) static void DS1302_DATAOUT_init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
@@ -56,6 +58,7 @@ static void DS1302_DATAOUT_init(void)
/** /**
* @brief 配置IO口为输入 * @brief 配置IO口为输入
*/ */
/* 函数作用:把 DS1302 数据引脚配置为浮空输入模式。 */
static void DS1302_DATAINPUT_init(void) static void DS1302_DATAINPUT_init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
@@ -67,6 +70,7 @@ static void DS1302_DATAINPUT_init(void)
/** /**
* @brief DS1302初始化 * @brief DS1302初始化
*/ */
/* 函数作用:初始化 DS1302 的时钟、数据和使能引脚。 */
void DS1302_Init(void) void DS1302_Init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
@@ -92,6 +96,7 @@ void DS1302_Init(void)
* @brief 向DS1302发送一字节数据(根据demo代码) * @brief 向DS1302发送一字节数据(根据demo代码)
* @param data 要发送的数据 * @param data 要发送的数据
*/ */
/* 函数作用:按 DS1302 时序向芯片写入一个字节。 */
static void DS1302_write_onebyte(uint8_t data) static void DS1302_write_onebyte(uint8_t data)
{ {
uint8_t count = 0; uint8_t count = 0;
@@ -119,6 +124,7 @@ static void DS1302_write_onebyte(uint8_t data)
* @param address 寄存器地址 * @param address 寄存器地址
* @param data 数据 * @param data 数据
*/ */
/* 函数作用:向 DS1302 指定寄存器写入一个字节数据。 */
void DS1302_WriteByte(uint8_t address, uint8_t data) void DS1302_WriteByte(uint8_t address, uint8_t data)
{ {
CE_L; CE_L;
@@ -141,6 +147,7 @@ void DS1302_WriteByte(uint8_t address, uint8_t data)
* @param address 寄存器地址 * @param address 寄存器地址
* @retval 读取到的数据 * @retval 读取到的数据
*/ */
/* 函数作用:从 DS1302 指定寄存器读取一个字节数据。 */
uint8_t DS1302_ReadByte(uint8_t address) uint8_t DS1302_ReadByte(uint8_t address)
{ {
uint8_t count = 0; uint8_t count = 0;
@@ -184,6 +191,7 @@ uint8_t DS1302_ReadByte(uint8_t address)
* @brief 设置DS1302时间 * @brief 设置DS1302时间
* @param time 时间结构体指针 * @param time 时间结构体指针
*/ */
/* 函数作用:把时间结构体转换为 BCD 后写入 DS1302。 */
void DS1302_SetTime(DS1302_Time* time) void DS1302_SetTime(DS1302_Time* time)
{ {
// 关闭写保护 // 关闭写保护
@@ -206,6 +214,7 @@ void DS1302_SetTime(DS1302_Time* time)
* @brief 读取DS1302时间 * @brief 读取DS1302时间
* @param time 时间结构体指针 * @param time 时间结构体指针
*/ */
/* 函数作用:读取 DS1302 时间寄存器并转换为十进制时间结构体。 */
void DS1302_GetTime(DS1302_Time* time) void DS1302_GetTime(DS1302_Time* time)
{ {
uint8_t read_time[7]; uint8_t read_time[7];
+5
View File
@@ -15,10 +15,15 @@ typedef struct {
} DS1302_Time; } DS1302_Time;
// 函数声明 // 函数声明
// 函数作用:初始化 DS1302 时钟芯片使用的 GPIO 引脚和通信状态。
void DS1302_Init(void); void DS1302_Init(void);
// 函数作用:把指定时间写入 DS1302 时钟芯片。
void DS1302_SetTime(DS1302_Time* time); void DS1302_SetTime(DS1302_Time* time);
// 函数作用:从 DS1302 时钟芯片读取当前日期和时间。
void DS1302_GetTime(DS1302_Time* time); void DS1302_GetTime(DS1302_Time* time);
// 函数作用:从 DS1302 指定寄存器地址读取一个字节数据。
uint8_t DS1302_ReadByte(uint8_t addr); uint8_t DS1302_ReadByte(uint8_t addr);
// 函数作用:向 DS1302 指定寄存器地址写入一个字节数据。
void DS1302_WriteByte(uint8_t addr, uint8_t dat); void DS1302_WriteByte(uint8_t addr, uint8_t dat);
#endif #endif
+4
View File
@@ -11,6 +11,7 @@ extern volatile uint8_t g_k210_rx_flag;
// 全局变量:存储解析后的人脸识别结果 // 全局变量:存储解析后的人脸识别结果
FaceRecognitionResult K210_FaceResult; FaceRecognitionResult K210_FaceResult;
/* 函数作用:初始化与 K210 通信的 USART3 串口和接收中断。 */
void K210_USART_Init(void) void K210_USART_Init(void)
{ {
// 根据连接图.md: K210使用USART3 (PB10/PB11) // 根据连接图.md: K210使用USART3 (PB10/PB11)
@@ -60,6 +61,7 @@ void K210_USART_Init(void)
* K210数据格式示例: "ID:2021001,NAME:Zhang_San,CONF:0.95" * K210数据格式示例: "ID:2021001,NAME:Zhang_San,CONF:0.95"
* 或者: "UNKNOWN" (未识别到人脸) * 或者: "UNKNOWN" (未识别到人脸)
*/ */
/* 函数作用:解析 K210 串口发送的人脸识别字符串并填充结果结构体。 */
uint8_t K210_ParseFaceData(const char* buffer, FaceRecognitionResult* result) uint8_t K210_ParseFaceData(const char* buffer, FaceRecognitionResult* result)
{ {
DEBUG_PRINT("[K210] Raw data: %s\r\n", buffer); DEBUG_PRINT("[K210] Raw data: %s\r\n", buffer);
@@ -109,6 +111,7 @@ uint8_t K210_ParseFaceData(const char* buffer, FaceRecognitionResult* result)
return 0; // 解析失败 return 0; // 解析失败
} }
/* 函数作用:检查 K210 接收完成标志,并在有新数据时解析识别结果。 */
uint8_t K210_GetRxFlag(void) uint8_t K210_GetRxFlag(void)
{ {
if (g_k210_rx_flag) if (g_k210_rx_flag)
@@ -129,6 +132,7 @@ uint8_t K210_GetRxFlag(void)
return 0; return 0;
} }
/* 函数作用:清除 K210 串口接收完成标志和计数器。 */
void K210_ClearRxFlag(void) void K210_ClearRxFlag(void)
{ {
g_k210_rx_flag = 0; g_k210_rx_flag = 0;
+4
View File
@@ -10,9 +10,13 @@
extern FaceRecognitionResult K210_FaceResult; extern FaceRecognitionResult K210_FaceResult;
// 声明公共函数 // 声明公共函数
// 函数作用:初始化 STM32 与 K210 通信用的 USART3 接口和接收中断。
void K210_USART_Init(void); void K210_USART_Init(void);
// 函数作用:返回 K210 串口接收完成标志,用于主循环判断是否有新识别结果。
uint8_t K210_GetRxFlag(void); uint8_t K210_GetRxFlag(void);
// 函数作用:清除 K210 串口接收完成标志,准备接收下一帧数据。
void K210_ClearRxFlag(void); void K210_ClearRxFlag(void);
// 函数作用:解析 K210 发来的识别结果字符串,填充人脸识别结果结构体。
uint8_t K210_ParseFaceData(const char* buffer, FaceRecognitionResult* result); uint8_t K210_ParseFaceData(const char* buffer, FaceRecognitionResult* result);
#endif #endif
+4
View File
@@ -6,6 +6,7 @@ static uint8_t g_fill_light_on = 0;
/** /**
* @brief 初始化光敏电阻ADC和补光灯GPIO * @brief 初始化光敏电阻ADC和补光灯GPIO
*/ */
/* 函数作用:初始化光敏电阻 ADC 输入和补光灯 GPIO 输出。 */
void LightSensor_Init(void) void LightSensor_Init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
@@ -60,6 +61,7 @@ void LightSensor_Init(void)
* @brief 获取光敏电阻ADC值 * @brief 获取光敏电阻ADC值
* @return ADC值 (0-4095),值越大表示光线越暗(电阻越大) * @return ADC值 (0-4095),值越大表示光线越暗(电阻越大)
*/ */
/* 函数作用:采集一次光敏电阻 ADC 数值。 */
uint16_t LightSensor_GetValue(void) uint16_t LightSensor_GetValue(void)
{ {
// 启动ADC转换 // 启动ADC转换
@@ -76,6 +78,7 @@ uint16_t LightSensor_GetValue(void)
* @brief 更新补光灯状态(在主循环中定期调用) * @brief 更新补光灯状态(在主循环中定期调用)
* 使用迟滞控制避免灯光频繁开关 * 使用迟滞控制避免灯光频繁开关
*/ */
/* 函数作用:根据环境光强自动打开或关闭补光灯。 */
void LightSensor_Update(void) void LightSensor_Update(void)
{ {
uint16_t light_value = LightSensor_GetValue(); uint16_t light_value = LightSensor_GetValue();
@@ -100,6 +103,7 @@ void LightSensor_Update(void)
* @brief 获取补光灯当前状态 * @brief 获取补光灯当前状态
* @return 1=亮,0=灭 * @return 1=亮,0=灭
*/ */
/* 函数作用:返回补光灯当前开关状态。 */
uint8_t LightSensor_IsLightOn(void) uint8_t LightSensor_IsLightOn(void)
{ {
return g_fill_light_on; return g_fill_light_on;
+8 -4
View File
@@ -22,9 +22,13 @@
// 使用迟滞区间避免频繁开关 // 使用迟滞区间避免频繁开关
// 函数声明 // 函数声明
void LightSensor_Init(void); // 初始化光敏电阻ADC和补光灯GPIO // 函数作用:初始化光敏电阻 ADC 输入和补光灯 GPIO 输出。
uint16_t LightSensor_GetValue(void); // 获取光敏电阻ADC值 void LightSensor_Init(void);
void LightSensor_Update(void); // 更新补光灯状态(主循环中调用) // 函数作用:读取光敏电阻 ADC 当前采样值。
uint8_t LightSensor_IsLightOn(void); // 获取补光灯当前状态 uint16_t LightSensor_GetValue(void);
// 函数作用:根据当前光照强度和迟滞阈值更新补光灯开关状态。
void LightSensor_Update(void);
// 函数作用:返回补光灯当前是否处于点亮状态。
uint8_t LightSensor_IsLightOn(void);
#endif #endif
+17
View File
@@ -12,6 +12,7 @@
/* ... 请确保您文件里这部分内容是完整的 ... */ /* ... 请确保您文件里这部分内容是完整的 ... */
/*引脚初始化*/ /*引脚初始化*/
/* 函数作用:初始化 OLED 软件 I2C 使用的 SCL 和 SDA GPIO。 */
void OLED_I2C_Init(void) void OLED_I2C_Init(void)
{ {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
@@ -28,6 +29,7 @@ void OLED_I2C_Init(void)
OLED_W_SDA(1); OLED_W_SDA(1);
} }
/* 函数作用:产生 OLED 软件 I2C 起始信号。 */
void OLED_I2C_Start(void) void OLED_I2C_Start(void)
{ {
OLED_W_SDA(1); OLED_W_SDA(1);
@@ -36,6 +38,7 @@ void OLED_I2C_Start(void)
OLED_W_SCL(0); OLED_W_SCL(0);
} }
/* 函数作用:产生 OLED 软件 I2C 停止信号。 */
void OLED_I2C_Stop(void) void OLED_I2C_Stop(void)
{ {
OLED_W_SDA(0); OLED_W_SDA(0);
@@ -43,6 +46,7 @@ void OLED_I2C_Stop(void)
OLED_W_SDA(1); OLED_W_SDA(1);
} }
/* 函数作用:通过软件 I2C 向 OLED 发送一个字节。 */
void OLED_I2C_SendByte(uint8_t Byte) void OLED_I2C_SendByte(uint8_t Byte)
{ {
uint8_t i; uint8_t i;
@@ -56,6 +60,7 @@ void OLED_I2C_SendByte(uint8_t Byte)
OLED_W_SCL(0); OLED_W_SCL(0);
} }
/* 函数作用:向 OLED 写入一条控制命令。 */
void OLED_WriteCommand(uint8_t Command) void OLED_WriteCommand(uint8_t Command)
{ {
OLED_I2C_Start(); OLED_I2C_Start();
@@ -65,6 +70,7 @@ void OLED_WriteCommand(uint8_t Command)
OLED_I2C_Stop(); OLED_I2C_Stop();
} }
/* 函数作用:向 OLED 写入一个显示数据字节。 */
void OLED_WriteData(uint8_t Data) void OLED_WriteData(uint8_t Data)
{ {
OLED_I2C_Start(); OLED_I2C_Start();
@@ -74,6 +80,7 @@ void OLED_WriteData(uint8_t Data)
OLED_I2C_Stop(); OLED_I2C_Stop();
} }
/* 函数作用:设置 OLED 显存写入光标位置。 */
void OLED_SetCursor(uint8_t Y, uint8_t X) void OLED_SetCursor(uint8_t Y, uint8_t X)
{ {
OLED_WriteCommand(0xB0 | Y); OLED_WriteCommand(0xB0 | Y);
@@ -81,6 +88,7 @@ void OLED_SetCursor(uint8_t Y, uint8_t X)
OLED_WriteCommand(0x00 | (X & 0x0F)); OLED_WriteCommand(0x00 | (X & 0x0F));
} }
/* 函数作用:清空 OLED 屏幕显示内容。 */
void OLED_Clear(void) void OLED_Clear(void)
{ {
uint8_t i, j; uint8_t i, j;
@@ -94,6 +102,7 @@ void OLED_Clear(void)
} }
} }
/* 函数作用:在指定行列显示一个 ASCII 字符。 */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char) void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{ {
uint8_t i; uint8_t i;
@@ -109,6 +118,7 @@ void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
} }
} }
/* 函数作用:从指定行列开始显示字符串。 */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String) void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{ {
uint8_t i; uint8_t i;
@@ -118,6 +128,7 @@ void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
} }
} }
/* 函数作用:计算整数 X 的 Y 次方,用于数字拆位显示。 */
uint32_t OLED_Pow(uint32_t X, uint32_t Y) uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{ {
uint32_t Result = 1; uint32_t Result = 1;
@@ -128,6 +139,7 @@ uint32_t OLED_Pow(uint32_t X, uint32_t Y)
return Result; return Result;
} }
/* 函数作用:在 OLED 上显示指定长度的无符号十进制数字。 */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length) void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{ {
uint8_t i; uint8_t i;
@@ -137,6 +149,7 @@ void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
} }
} }
/* 函数作用:在 OLED 上显示带正负号的十进制数字。 */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length) void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{ {
uint8_t i; uint8_t i;
@@ -157,6 +170,7 @@ void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Le
} }
} }
/* 函数作用:在 OLED 上显示指定长度的十六进制数字。 */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length) void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{ {
uint8_t i, SingleNumber; uint8_t i, SingleNumber;
@@ -174,6 +188,7 @@ void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Leng
} }
} }
/* 函数作用:在 OLED 上显示指定长度的二进制数字。 */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length) void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{ {
uint8_t i; uint8_t i;
@@ -191,6 +206,7 @@ void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Leng
* @param num 要显示的汉字在OLED_F16x16_CN字模数组中的索引 * @param num 要显示的汉字在OLED_F16x16_CN字模数组中的索引
* @retval 无 * @retval 无
*/ */
/* 函数作用:按照字模索引在 OLED 上显示一个 16x16 汉字。 */
void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t num) void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t num)
{ {
uint8_t i; uint8_t i;
@@ -219,6 +235,7 @@ void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t num)
/* ... OLED_Init() 函数保持不变 ... */ /* ... OLED_Init() 函数保持不变 ... */
/* 函数作用:初始化 OLED 控制器参数并清屏。 */
void OLED_Init(void) void OLED_Init(void)
{ {
uint32_t i, j; uint32_t i, j;
+9
View File
@@ -6,16 +6,25 @@
#include "stm32f10x.h" #include "stm32f10x.h"
// 函数作用:初始化 OLED 屏幕通信接口并完成显示控制器基础配置。
void OLED_Init(void); void OLED_Init(void);
// 函数作用:清空 OLED 显示缓冲区或屏幕内容。
void OLED_Clear(void); void OLED_Clear(void);
// 函数作用:在指定行列显示单个 ASCII 字符。
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char); void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
// 函数作用:从指定行列开始显示字符串。
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String); void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
// 函数作用:在指定位置显示无符号十进制数字。
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length); void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
// 函数作用:在指定位置显示带符号十进制数字。
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length); void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
// 函数作用:在指定位置显示十六进制数字。
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length); void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
// 函数作用:在指定位置显示二进制数字。
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length); void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
// 添加显示汉字的函数声明 // 添加显示汉字的函数声明
// 函数作用:在指定行列显示字库中编号对应的汉字。
void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t num); void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t num);
#endif #endif
+5
View File
@@ -7,6 +7,7 @@ char RxBuffer[RX_BUFFER_SIZE];
uint16_t RxCounter = 0; uint16_t RxCounter = 0;
// 初始化ESP8266所用的串口 (根据连接图.md: USART1 PA9/PA10) // 初始化ESP8266所用的串口 (根据连接图.md: USART1 PA9/PA10)
/* 函数作用:初始化与 ESP8266 通信的 USART1 串口和接收中断。 */
void Serial_Init(void) void Serial_Init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
@@ -46,6 +47,7 @@ void Serial_Init(void)
} }
// 发送字符串 // 发送字符串
/* 函数作用:通过 USART1 向 ESP8266 发送字符串。 */
void Serial_SendString(const char* String) void Serial_SendString(const char* String)
{ {
for (uint32_t i = 0; String[i] != '\0'; i++) for (uint32_t i = 0; String[i] != '\0'; i++)
@@ -56,12 +58,14 @@ void Serial_SendString(const char* String)
} }
// 获取接收缓冲区 // 获取接收缓冲区
/* 函数作用:返回 USART1 接收缓冲区指针。 */
char* Serial_GetRxBuffer(void) char* Serial_GetRxBuffer(void)
{ {
return RxBuffer; return RxBuffer;
} }
// 清空接收缓冲区 // 清空接收缓冲区
/* 函数作用:清空 USART1 接收缓冲区和接收计数。 */
void Serial_ClearRxBuffer(void) void Serial_ClearRxBuffer(void)
{ {
memset(RxBuffer, 0, RX_BUFFER_SIZE); memset(RxBuffer, 0, RX_BUFFER_SIZE);
@@ -69,6 +73,7 @@ void Serial_ClearRxBuffer(void)
} }
// USART1中断服务函数 (ESP8266) // USART1中断服务函数 (ESP8266)
/* 函数作用:接收 ESP8266 串口返回数据并写入环形缓冲区。 */
void USART1_IRQHandler(void) void USART1_IRQHandler(void)
{ {
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
+11 -5
View File
@@ -4,14 +4,20 @@
#include <stdio.h> #include <stdio.h>
#include "stm32f10x.h" #include "stm32f10x.h"
void Serial_Init(void); // 初始化串口 // 函数作用:初始化调试/通信串口及其接收缓冲区。
void Serial_SendByte(uint8_t Byte); // 发送一个字节 void Serial_Init(void);
void Serial_SendString(const char* String); // 发送字符串 // 函数作用:通过串口发送一个字节。
char* Serial_GetRxBuffer(void); // 获取接收缓冲区指针 void Serial_SendByte(uint8_t Byte);
void Serial_ClearRxBuffer(void); // 清空接收缓冲区 // 函数作用:通过串口连续发送以空字符结尾的字符串。
void Serial_SendString(const char* String);
// 函数作用:返回串口接收缓冲区指针,供主循环解析接收到的数据。
char* Serial_GetRxBuffer(void);
// 函数作用:清空串口接收缓冲区并复位接收状态。
void Serial_ClearRxBuffer(void);
// 注意:Get_Time_ms() 函数与串口无关,应该在 `Delay.h` 中声明。 // 注意:Get_Time_ms() 函数与串口无关,应该在 `Delay.h` 中声明。
// 我们暂时将它与串口放一起,但更规范的做法是分离。 // 我们暂时将它与串口放一起,但更规范的做法是分离。
// 函数作用:返回系统启动以来经过的毫秒数。
uint32_t Get_Time_ms(void); uint32_t Get_Time_ms(void);
#endif #endif
+18
View File
@@ -54,6 +54,7 @@ static const uint8_t Rcon[11] = {
#define getSBoxInvert(num) (rsbox[(num)]) #define getSBoxInvert(num) (rsbox[(num)])
// 密钥扩展 // 密钥扩展
/* 函数作用:根据 AES-128 主密钥生成每轮加密使用的轮密钥。 */
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{ {
unsigned i, j, k; unsigned i, j, k;
@@ -102,6 +103,7 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
} }
// AddRoundKey // AddRoundKey
/* 函数作用:将当前状态矩阵与指定轮密钥进行异或。 */
static void AddRoundKey(uint8_t round, uint8_t* state, const uint8_t* RoundKey) static void AddRoundKey(uint8_t round, uint8_t* state, const uint8_t* RoundKey)
{ {
uint8_t i, j; uint8_t i, j;
@@ -113,6 +115,7 @@ static void AddRoundKey(uint8_t round, uint8_t* state, const uint8_t* RoundKey)
} }
// SubBytes // SubBytes
/* 函数作用:使用 AES S 盒对状态矩阵进行字节替换。 */
static void SubBytes(uint8_t* state) static void SubBytes(uint8_t* state)
{ {
uint8_t i; uint8_t i;
@@ -122,6 +125,7 @@ static void SubBytes(uint8_t* state)
} }
// ShiftRows // ShiftRows
/* 函数作用:执行 AES 加密流程中的行移位变换。 */
static void ShiftRows(uint8_t* state) static void ShiftRows(uint8_t* state)
{ {
uint8_t temp; uint8_t temp;
@@ -150,12 +154,14 @@ static void ShiftRows(uint8_t* state)
} }
// xtime (用于MixColumns) // xtime (用于MixColumns)
/* 函数作用:在 AES 有限域中执行乘以 2 的运算。 */
static uint8_t xtime(uint8_t x) static uint8_t xtime(uint8_t x)
{ {
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
} }
// MixColumns // MixColumns
/* 函数作用:执行 AES 加密流程中的列混淆变换。 */
static void MixColumns(uint8_t* state) static void MixColumns(uint8_t* state)
{ {
uint8_t i; uint8_t i;
@@ -184,6 +190,7 @@ static void MixColumns(uint8_t* state)
} }
// Cipher - AES加密核心 // Cipher - AES加密核心
/* 函数作用:对 16 字节状态块执行完整 AES 加密。 */
static void Cipher(uint8_t* state, const uint8_t* RoundKey) static void Cipher(uint8_t* state, const uint8_t* RoundKey)
{ {
uint8_t round = 0; uint8_t round = 0;
@@ -205,6 +212,7 @@ static void Cipher(uint8_t* state, const uint8_t* RoundKey)
AddRoundKey(10, state, RoundKey); AddRoundKey(10, state, RoundKey);
} }
/* 函数作用:在 AES 有限域中执行两个字节的乘法。 */
static uint8_t Multiply(uint8_t x, uint8_t y) static uint8_t Multiply(uint8_t x, uint8_t y)
{ {
return (((y & 1) * x) ^ return (((y & 1) * x) ^
@@ -214,6 +222,7 @@ static uint8_t Multiply(uint8_t x, uint8_t y)
(((y >> 4) & 1) * xtime(xtime(xtime(xtime(x)))))); (((y >> 4) & 1) * xtime(xtime(xtime(xtime(x))))));
} }
/* 函数作用:使用 AES 逆 S 盒对状态矩阵进行逆字节替换。 */
static void InvSubBytes(uint8_t* state) static void InvSubBytes(uint8_t* state)
{ {
uint8_t i; uint8_t i;
@@ -222,6 +231,7 @@ static void InvSubBytes(uint8_t* state)
} }
} }
/* 函数作用:执行 AES 解密流程中的逆行移位变换。 */
static void InvShiftRows(uint8_t* state) static void InvShiftRows(uint8_t* state)
{ {
uint8_t temp; uint8_t temp;
@@ -245,6 +255,7 @@ static void InvShiftRows(uint8_t* state)
state[15] = temp; state[15] = temp;
} }
/* 函数作用:执行 AES 解密流程中的逆列混淆变换。 */
static void InvMixColumns(uint8_t* state) static void InvMixColumns(uint8_t* state)
{ {
uint8_t i; uint8_t i;
@@ -263,6 +274,7 @@ static void InvMixColumns(uint8_t* state)
} }
} }
/* 函数作用:对 16 字节状态块执行完整 AES 解密。 */
static void InvCipher(uint8_t* state, const uint8_t* RoundKey) static void InvCipher(uint8_t* state, const uint8_t* RoundKey)
{ {
uint8_t round; uint8_t round;
@@ -282,22 +294,26 @@ static void InvCipher(uint8_t* state, const uint8_t* RoundKey)
// ========== 公开API函数 ========== // ========== 公开API函数 ==========
/* 函数作用:初始化 AES 上下文并生成轮密钥。 */
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
{ {
KeyExpansion(ctx->RoundKey, key); KeyExpansion(ctx->RoundKey, key);
} }
/* 函数作用:初始化 AES 上下文并设置 CBC 模式 IV。 */
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
{ {
KeyExpansion(ctx->RoundKey, key); KeyExpansion(ctx->RoundKey, key);
memcpy(ctx->Iv, iv, AES_BLOCKLEN); memcpy(ctx->Iv, iv, AES_BLOCKLEN);
} }
/* 函数作用:对单个 16 字节数据块执行 AES-ECB 加密。 */
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
{ {
Cipher(buf, ctx->RoundKey); Cipher(buf, ctx->RoundKey);
} }
/* 函数作用:使用 AES-CBC 模式加密指定长度的数据缓冲区。 */
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{ {
size_t i; size_t i;
@@ -317,11 +333,13 @@ void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
} }
} }
/* 函数作用:对单个 16 字节数据块执行 AES-ECB 解密。 */
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
{ {
InvCipher(buf, ctx->RoundKey); InvCipher(buf, ctx->RoundKey);
} }
/* 函数作用:使用 AES-CBC 模式解密指定长度的数据缓冲区。 */
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{ {
size_t i; size_t i;
+6
View File
@@ -20,6 +20,7 @@ struct AES_ctx
* @param ctx AES上下文结构 * @param ctx AES上下文结构
* @param key 16字节密钥 * @param key 16字节密钥
*/ */
// 函数作用:根据 16 字节密钥初始化 AES 上下文并生成轮密钥。
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
/** /**
@@ -27,6 +28,7 @@ void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
* @param ctx AES上下文 * @param ctx AES上下文
* @param buf 要加密的数据(16字节块) * @param buf 要加密的数据(16字节块)
*/ */
// 函数作用:使用 AES-ECB 模式加密单个 16 字节数据块。
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
/** /**
@@ -34,6 +36,7 @@ void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
* @param ctx AES上下文 * @param ctx AES上下文
* @param buf 要解密的数据(16字节块) * @param buf 要解密的数据(16字节块)
*/ */
// 函数作用:使用 AES-ECB 模式解密单个 16 字节数据块。
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
/** /**
@@ -43,6 +46,7 @@ void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
* @param length 数据长度(必须是16的倍数) * @param length 数据长度(必须是16的倍数)
* @param iv 初始化向量(16字节) * @param iv 初始化向量(16字节)
*/ */
// 函数作用:使用上下文中的 IV 按 AES-CBC 模式加密指定长度的缓冲区。
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
/** /**
@@ -52,6 +56,7 @@ void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
* @param length 数据长度(必须是16的倍数) * @param length 数据长度(必须是16的倍数)
* @param iv 初始化向量(16字节) * @param iv 初始化向量(16字节)
*/ */
// 函数作用:使用上下文中的 IV 按 AES-CBC 模式解密指定长度的缓冲区。
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
/** /**
@@ -60,6 +65,7 @@ void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
* @param key 16字节密钥 * @param key 16字节密钥
* @param iv 16字节初始化向量 * @param iv 16字节初始化向量
*/ */
// 函数作用:使用 16 字节密钥和 16 字节 IV 初始化 AES-CBC 上下文。
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
#endif // _AES_H_ #endif // _AES_H_
+13
View File
@@ -34,6 +34,7 @@ static const uint8_t Rcon[11] = {
#define getSBoxValue(num) (sbox[(num)]) #define getSBoxValue(num) (sbox[(num)])
// 密钥扩展 // 密钥扩展
/* 函数作用:根据 AES-128 主密钥生成每轮加密使用的轮密钥。 */
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{ {
unsigned i, j, k; unsigned i, j, k;
@@ -82,6 +83,7 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
} }
// AddRoundKey // AddRoundKey
/* 函数作用:将当前状态矩阵与指定轮密钥进行异或。 */
static void AddRoundKey(uint8_t round, uint8_t* state, const uint8_t* RoundKey) static void AddRoundKey(uint8_t round, uint8_t* state, const uint8_t* RoundKey)
{ {
uint8_t i, j; uint8_t i, j;
@@ -93,6 +95,7 @@ static void AddRoundKey(uint8_t round, uint8_t* state, const uint8_t* RoundKey)
} }
// SubBytes // SubBytes
/* 函数作用:使用 AES S 盒对状态矩阵进行字节替换。 */
static void SubBytes(uint8_t* state) static void SubBytes(uint8_t* state)
{ {
uint8_t i; uint8_t i;
@@ -102,6 +105,7 @@ static void SubBytes(uint8_t* state)
} }
// ShiftRows // ShiftRows
/* 函数作用:执行 AES 加密流程中的行移位变换。 */
static void ShiftRows(uint8_t* state) static void ShiftRows(uint8_t* state)
{ {
uint8_t temp; uint8_t temp;
@@ -130,12 +134,14 @@ static void ShiftRows(uint8_t* state)
} }
// xtime (用于MixColumns) // xtime (用于MixColumns)
/* 函数作用:在 AES 有限域中执行乘以 2 的运算。 */
static uint8_t xtime(uint8_t x) static uint8_t xtime(uint8_t x)
{ {
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
} }
// MixColumns // MixColumns
/* 函数作用:执行 AES 加密流程中的列混淆变换。 */
static void MixColumns(uint8_t* state) static void MixColumns(uint8_t* state)
{ {
uint8_t i; uint8_t i;
@@ -164,6 +170,7 @@ static void MixColumns(uint8_t* state)
} }
// Cipher - AES加密核心 // Cipher - AES加密核心
/* 函数作用:对 16 字节状态块执行完整 AES 加密。 */
static void Cipher(uint8_t* state, const uint8_t* RoundKey) static void Cipher(uint8_t* state, const uint8_t* RoundKey)
{ {
uint8_t round = 0; uint8_t round = 0;
@@ -187,22 +194,26 @@ static void Cipher(uint8_t* state, const uint8_t* RoundKey)
// ========== 公开API函数 ========== // ========== 公开API函数 ==========
/* 函数作用:初始化 AES 上下文并生成轮密钥。 */
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
{ {
KeyExpansion(ctx->RoundKey, key); KeyExpansion(ctx->RoundKey, key);
} }
/* 函数作用:初始化 AES 上下文并设置 CBC 模式 IV。 */
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
{ {
KeyExpansion(ctx->RoundKey, key); KeyExpansion(ctx->RoundKey, key);
memcpy(ctx->Iv, iv, AES_BLOCKLEN); memcpy(ctx->Iv, iv, AES_BLOCKLEN);
} }
/* 函数作用:对单个 16 字节数据块执行 AES-ECB 加密。 */
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
{ {
Cipher(buf, ctx->RoundKey); Cipher(buf, ctx->RoundKey);
} }
/* 函数作用:使用 AES-CBC 模式加密指定长度的数据缓冲区。 */
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{ {
size_t i; size_t i;
@@ -223,12 +234,14 @@ void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
} }
// STM32端不需要解密功能 // STM32端不需要解密功能
/* 函数作用:对单个 16 字节数据块执行 AES-ECB 解密。 */
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
{ {
(void)ctx; (void)ctx;
(void)buf; (void)buf;
} }
/* 函数作用:使用 AES-CBC 模式解密指定长度的数据缓冲区。 */
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{ {
(void)ctx; (void)ctx;
+6
View File
@@ -20,6 +20,7 @@ struct AES_ctx
* @param ctx AES上下文结构 * @param ctx AES上下文结构
* @param key 16字节密钥 * @param key 16字节密钥
*/ */
// 函数作用:根据 16 字节密钥初始化 AES 上下文并生成轮密钥。
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
/** /**
@@ -28,6 +29,7 @@ void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
* @param key 16字节密钥 * @param key 16字节密钥
* @param iv 16字节初始化向量 * @param iv 16字节初始化向量
*/ */
// 函数作用:使用 16 字节密钥和 16 字节 IV 初始化 AES-CBC 上下文。
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
/** /**
@@ -35,6 +37,7 @@ void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
* @param ctx AES上下文 * @param ctx AES上下文
* @param buf 要加密的数据(16字节块) * @param buf 要加密的数据(16字节块)
*/ */
// 函数作用:使用 AES-ECB 模式加密单个 16 字节数据块。
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
/** /**
@@ -42,6 +45,7 @@ void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
* @param ctx AES上下文 * @param ctx AES上下文
* @param buf 要解密的数据(16字节块) * @param buf 要解密的数据(16字节块)
*/ */
// 函数作用:使用 AES-ECB 模式解密单个 16 字节数据块。
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
/** /**
@@ -50,6 +54,7 @@ void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
* @param buf 要加密的数据 * @param buf 要加密的数据
* @param length 数据长度(必须是16的倍数) * @param length 数据长度(必须是16的倍数)
*/ */
// 函数作用:使用上下文中的 IV 按 AES-CBC 模式加密指定长度的缓冲区。
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
/** /**
@@ -58,6 +63,7 @@ void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
* @param buf 要解密的数据 * @param buf 要解密的数据
* @param length 数据长度(必须是16的倍数) * @param length 数据长度(必须是16的倍数)
*/ */
// 函数作用:使用上下文中的 IV 按 AES-CBC 模式解密指定长度的缓冲区。
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
#endif // _AES_H_ #endif // _AES_H_
+3
View File
@@ -9,6 +9,7 @@
static const char base64_chars[] = static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* 函数作用:将二进制数据编码为 Base64 字符串。 */
uint32_t base64_encode(const uint8_t* input, uint32_t input_length, char* output) uint32_t base64_encode(const uint8_t* input, uint32_t input_length, char* output)
{ {
uint32_t i, j; uint32_t i, j;
@@ -41,6 +42,7 @@ uint32_t base64_encode(const uint8_t* input, uint32_t input_length, char* output
return output_length; return output_length;
} }
/* 函数作用:把 Base64 字符转换为 6 位数值。 */
static uint8_t base64_char_value(char c) static uint8_t base64_char_value(char c)
{ {
if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'A' && c <= 'Z') return c - 'A';
@@ -51,6 +53,7 @@ static uint8_t base64_char_value(char c)
return 0; return 0;
} }
/* 函数作用:将 Base64 字符串解码为二进制数据。 */
uint32_t base64_decode(const char* input, uint32_t input_length, uint8_t* output) uint32_t base64_decode(const char* input, uint32_t input_length, uint8_t* output)
{ {
uint32_t i, j; uint32_t i, j;
+2
View File
@@ -13,6 +13,7 @@
* *
* 注意:output缓冲区大小至少需要 ((input_length + 2) / 3) * 4 + 1 字节 * 注意:output缓冲区大小至少需要 ((input_length + 2) / 3) * 4 + 1 字节
*/ */
// 函数作用:将二进制输入数据编码为 Base64 字符串并返回输出长度。
uint32_t base64_encode(const uint8_t* input, uint32_t input_length, char* output); uint32_t base64_encode(const uint8_t* input, uint32_t input_length, char* output);
/** /**
@@ -22,6 +23,7 @@ uint32_t base64_encode(const uint8_t* input, uint32_t input_length, char* output
* @param output 输出缓冲区 * @param output 输出缓冲区
* @return 解码后的数据长度 * @return 解码后的数据长度
*/ */
// 函数作用:将 Base64 字符串解码为二进制数据并返回解码长度。
uint32_t base64_decode(const char* input, uint32_t input_length, uint8_t* output); uint32_t base64_decode(const char* input, uint32_t input_length, uint8_t* output);
/** /**
+15
View File
@@ -25,11 +25,13 @@ extern const char* HTTP_API_TOKEN;
extern uint8_t g_server_connected; extern uint8_t g_server_connected;
/* --- 私有辅助函数 --- */ /* --- 私有辅助函数 --- */
/* 函数作用:向 ESP8266 串口发送一条 AT 指令并追加回车换行。 */
static void ESP8266_SendCmd(const char* cmd) { static void ESP8266_SendCmd(const char* cmd) {
Serial_SendString(cmd); Serial_SendString(cmd);
Serial_SendString("\r\n"); Serial_SendString("\r\n");
} }
/* 函数作用:在指定超时时间内等待 ESP8266 返回期望关键字。 */
static uint8_t ESP8266_WaitForAck(const char* ack, uint32_t timeout) { static uint8_t ESP8266_WaitForAck(const char* ack, uint32_t timeout) {
uint32_t time_start = Get_Time_ms(); uint32_t time_start = Get_Time_ms();
uint32_t time_elapsed; uint32_t time_elapsed;
@@ -57,11 +59,13 @@ static uint8_t ESP8266_WaitForAck(const char* ack, uint32_t timeout) {
return ESP8266_FAIL; return ESP8266_FAIL;
} }
/* 函数作用:判断指定年份是否为闰年。 */
static uint8_t IsLeapYear(uint16_t year) static uint8_t IsLeapYear(uint16_t year)
{ {
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0; return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0;
} }
/* 函数作用:返回指定年份月份的天数。 */
static uint8_t DaysInMonth(uint16_t year, uint8_t month) static uint8_t DaysInMonth(uint16_t year, uint8_t month)
{ {
static const uint8_t days_table[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; static const uint8_t days_table[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
@@ -69,6 +73,7 @@ static uint8_t DaysInMonth(uint16_t year, uint8_t month)
return days_table[month - 1]; return days_table[month - 1];
} }
/* 函数作用:把 Unix 时间戳转换为北京时间结构体。 */
static void EpochToDateTimeUTC8(uint32_t epoch_seconds, ESP8266_DateTime* datetime) static void EpochToDateTimeUTC8(uint32_t epoch_seconds, ESP8266_DateTime* datetime)
{ {
// 转为北京时间(UTC+8) // 转为北京时间(UTC+8)
@@ -99,6 +104,7 @@ static void EpochToDateTimeUTC8(uint32_t epoch_seconds, ESP8266_DateTime* dateti
datetime->day = (uint8_t)(days + 1U); datetime->day = (uint8_t)(days + 1U);
} }
/* 函数作用:从 HTTP 响应中复制正文,并在响应加密时完成解密。 */
static uint8_t ESP8266_CopyDecryptedBody(char* response, static uint8_t ESP8266_CopyDecryptedBody(char* response,
char* body_start, char* body_start,
uint16_t body_len, uint16_t body_len,
@@ -137,6 +143,7 @@ static uint8_t ESP8266_CopyDecryptedBody(char* response,
/* --- 公共接口函数实现 --- */ /* --- 公共接口函数实现 --- */
/* 函数作用:初始化 ESP8266 AT 模式、WiFi 模式和 TCP 单连接模式。 */
uint8_t ESP8266_Setup(void) uint8_t ESP8266_Setup(void)
{ {
ESP8266_SendCmd("+++"); ESP8266_SendCmd("+++");
@@ -159,6 +166,7 @@ uint8_t ESP8266_Setup(void)
return ESP8266_SUCCESS; return ESP8266_SUCCESS;
} }
/* 函数作用:连接指定 SSID 和密码的 WiFi 热点。 */
uint8_t ESP8266_ConnectWiFi(const char* ssid, const char* password) uint8_t ESP8266_ConnectWiFi(const char* ssid, const char* password)
{ {
char cmd_buffer[128]; char cmd_buffer[128];
@@ -172,6 +180,7 @@ uint8_t ESP8266_ConnectWiFi(const char* ssid, const char* password)
/** /**
* @brief 连接到HTTP服务器(新增) * @brief 连接到HTTP服务器(新增)
*/ */
/* 函数作用:与服务端建立 TCP 连接,为后续 HTTP 请求做准备。 */
uint8_t ESP8266_ConnectHTTPServer(const char* ip, const char* port) uint8_t ESP8266_ConnectHTTPServer(const char* ip, const char* port)
{ {
char cmd_buffer[100]; char cmd_buffer[100];
@@ -215,6 +224,7 @@ uint8_t ESP8266_ConnectHTTPServer(const char* ip, const char* port)
/** /**
* @brief 发送加密数据(HTTP POST请求) * @brief 发送加密数据(HTTP POST请求)
*/ */
/* 函数作用:通过 HTTP POST 上传 AES 加密后的考勤 JSON 数据。 */
uint8_t ESP8266_SendEncryptedData(const char* encrypted_data) uint8_t ESP8266_SendEncryptedData(const char* encrypted_data)
{ {
char http_request[1024]; char http_request[1024];
@@ -353,6 +363,7 @@ uint8_t ESP8266_SendEncryptedData(const char* encrypted_data)
return ESP8266_FAIL; return ESP8266_FAIL;
} }
/* 函数作用:从服务端时间接口获取 Unix 时间戳并转换为本地时间。 */
uint8_t ESP8266_GetNetworkTime(ESP8266_DateTime* datetime) uint8_t ESP8266_GetNetworkTime(ESP8266_DateTime* datetime)
{ {
char response_buffer[256]; char response_buffer[256];
@@ -405,6 +416,7 @@ uint8_t ESP8266_GetNetworkTime(ESP8266_DateTime* datetime)
return ESP8266_SUCCESS; return ESP8266_SUCCESS;
} }
/* 函数作用:查询 ESP8266 当前 TCP/WiFi 连接状态。 */
uint8_t ESP8266_CheckConnection(void) uint8_t ESP8266_CheckConnection(void)
{ {
char* response; char* response;
@@ -442,6 +454,7 @@ uint8_t ESP8266_CheckConnection(void)
/** /**
* @brief 发送HTTP GET请求并接收响应 * @brief 发送HTTP GET请求并接收响应
*/ */
/* 函数作用:发送带 Token 的 HTTP GET 请求,并返回解密后的响应正文。 */
uint8_t ESP8266_HttpGet(const char* path, char* response_buffer, uint16_t buffer_size) uint8_t ESP8266_HttpGet(const char* path, char* response_buffer, uint16_t buffer_size)
{ {
char http_request[320]; char http_request[320];
@@ -592,6 +605,7 @@ uint8_t ESP8266_HttpGet(const char* path, char* response_buffer, uint16_t buffer
* @param slot_end 时段结束时间(格式"HH:MM") * @param slot_end 时段结束时间(格式"HH:MM")
* @retval 1 表示已签到(重复), 0 表示未签到 * @retval 1 表示已签到(重复), 0 表示未签到
*/ */
/* 函数作用:向服务器查询指定学生在给定时段内是否重复签到。 */
uint8_t ESP8266_CheckDuplicate(const char* student_id, const char* slot_start, const char* slot_end) uint8_t ESP8266_CheckDuplicate(const char* student_id, const char* slot_start, const char* slot_end)
{ {
char path[128]; char path[128];
@@ -639,6 +653,7 @@ uint8_t ESP8266_CheckDuplicate(const char* student_id, const char* slot_start, c
* @param buffer_size 缓冲区大小 * @param buffer_size 缓冲区大小
* @retval 成功下载的学号数量 * @retval 成功下载的学号数量
*/ */
/* 函数作用:下载指定时间段内今日已签到学生列表,用于本地查重缓存。 */
uint8_t ESP8266_DownloadTodayRecords(const char* slot_start, const char* slot_end, char* student_ids, uint16_t buffer_size) uint8_t ESP8266_DownloadTodayRecords(const char* slot_start, const char* slot_end, char* student_ids, uint16_t buffer_size)
{ {
char path[128]; char path[128];
+9
View File
@@ -25,6 +25,7 @@ typedef struct {
* @brief 对ESP8266模块进行基础设置 * @brief 对ESP8266模块进行基础设置
* @retval 1 表示成功, 0 表示失败 * @retval 1 表示成功, 0 表示失败
*/ */
// 函数作用:初始化 ESP8266 模块并配置基础 AT 工作模式。
uint8_t ESP8266_Setup(void); uint8_t ESP8266_Setup(void);
/** /**
@@ -33,6 +34,7 @@ uint8_t ESP8266_Setup(void);
* @param password WiFi的密码 * @param password WiFi的密码
* @retval 1 表示成功, 0 表示失败 * @retval 1 表示成功, 0 表示失败
*/ */
// 函数作用:控制 ESP8266 连接指定 WiFi 网络。
uint8_t ESP8266_ConnectWiFi(const char* ssid, const char* password); uint8_t ESP8266_ConnectWiFi(const char* ssid, const char* password);
/** /**
@@ -41,6 +43,7 @@ uint8_t ESP8266_ConnectWiFi(const char* ssid, const char* password);
* @param port 服务器的端口号 * @param port 服务器的端口号
* @retval 1 表示成功, 0 表示失败 * @retval 1 表示成功, 0 表示失败
*/ */
// 函数作用:控制 ESP8266 与指定 HTTP 服务器建立 TCP 连接。
uint8_t ESP8266_ConnectHTTPServer(const char* ip, const char* port); uint8_t ESP8266_ConnectHTTPServer(const char* ip, const char* port);
/** /**
@@ -48,12 +51,14 @@ uint8_t ESP8266_ConnectHTTPServer(const char* ip, const char* port);
* @param encrypted_data 加密后的Base64数据 * @param encrypted_data 加密后的Base64数据
* @retval 1 表示成功, 0 表示失败 * @retval 1 表示成功, 0 表示失败
*/ */
// 函数作用:通过 ESP8266 发送加密后的考勤 HTTP POST 数据。
uint8_t ESP8266_SendEncryptedData(const char* encrypted_data); uint8_t ESP8266_SendEncryptedData(const char* encrypted_data);
/** /**
* @brief 检查TCP连接是否正常 * @brief 检查TCP连接是否正常
* @retval 1 表示已连接, 0 表示未连接 * @retval 1 表示已连接, 0 表示未连接
*/ */
// 函数作用:检查 ESP8266 当前 TCP/网络连接是否仍然可用。
uint8_t ESP8266_CheckConnection(void); uint8_t ESP8266_CheckConnection(void);
/** /**
@@ -61,6 +66,7 @@ uint8_t ESP8266_CheckConnection(void);
* @param datetime 时间结构体指针,用于存储获取的时间 * @param datetime 时间结构体指针,用于存储获取的时间
* @retval 1 表示成功, 0 表示失败 * @retval 1 表示成功, 0 表示失败
*/ */
// 函数作用:从网络时间服务或服务端接口获取当前日期时间。
uint8_t ESP8266_GetNetworkTime(ESP8266_DateTime* datetime); uint8_t ESP8266_GetNetworkTime(ESP8266_DateTime* datetime);
/** /**
@@ -70,6 +76,7 @@ uint8_t ESP8266_GetNetworkTime(ESP8266_DateTime* datetime);
* @param buffer_size 缓冲区大小 * @param buffer_size 缓冲区大小
* @retval 1 表示成功, 0 表示失败 * @retval 1 表示成功, 0 表示失败
*/ */
// 函数作用:通过 ESP8266 发起 HTTP GET 请求并把响应写入缓冲区。
uint8_t ESP8266_HttpGet(const char* path, char* response_buffer, uint16_t buffer_size); uint8_t ESP8266_HttpGet(const char* path, char* response_buffer, uint16_t buffer_size);
/** /**
@@ -79,6 +86,7 @@ uint8_t ESP8266_HttpGet(const char* path, char* response_buffer, uint16_t buffer
* @param slot_end 时段结束时间(格式"HH:MM") * @param slot_end 时段结束时间(格式"HH:MM")
* @retval 1 表示已签到(重复), 0 表示未签到 * @retval 1 表示已签到(重复), 0 表示未签到
*/ */
// 函数作用:调用服务端查重接口,判断学生在指定时段是否已签到。
uint8_t ESP8266_CheckDuplicate(const char* student_id, const char* slot_start, const char* slot_end); uint8_t ESP8266_CheckDuplicate(const char* student_id, const char* slot_start, const char* slot_end);
/** /**
@@ -89,6 +97,7 @@ uint8_t ESP8266_CheckDuplicate(const char* student_id, const char* slot_start, c
* @param buffer_size 缓冲区大小 * @param buffer_size 缓冲区大小
* @retval 成功下载的学号数量 * @retval 成功下载的学号数量
*/ */
// 函数作用:下载指定时段内今日已签到学生列表,用于本地去重缓存恢复。
uint8_t ESP8266_DownloadTodayRecords(const char* slot_start, const char* slot_end, char* student_ids, uint16_t buffer_size); uint8_t ESP8266_DownloadTodayRecords(const char* slot_start, const char* slot_end, char* student_ids, uint16_t buffer_size);
#endif #endif
+6
View File
@@ -10,6 +10,7 @@ static char debug_buffer[256];
/** /**
* @brief 初始化调试串口(USART2, PA2=TX, PA3=RX) * @brief 初始化调试串口(USART2, PA2=TX, PA3=RX)
*/ */
/* 函数作用:初始化 USART2 调试串口并输出启动日志。 */
void Debug_Init(void) void Debug_Init(void)
{ {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
@@ -52,6 +53,7 @@ void Debug_Init(void)
/** /**
* @brief 通过调试串口发送一个字节 * @brief 通过调试串口发送一个字节
*/ */
/* 函数作用:通过 USART2 发送单个调试字节。 */
static void Debug_SendByte(uint8_t byte) static void Debug_SendByte(uint8_t byte)
{ {
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
@@ -61,6 +63,7 @@ static void Debug_SendByte(uint8_t byte)
/** /**
* @brief 通过调试串口发送字符串 * @brief 通过调试串口发送字符串
*/ */
/* 函数作用:通过 USART2 连续发送调试字符串。 */
static void Debug_SendString(const char* str) static void Debug_SendString(const char* str)
{ {
while (*str) while (*str)
@@ -72,6 +75,7 @@ static void Debug_SendString(const char* str)
/** /**
* @brief 格式化调试信息输出(类似printf) * @brief 格式化调试信息输出(类似printf)
*/ */
/* 函数作用:格式化调试信息并通过串口输出。 */
void Debug_Printf(const char* format, ...) void Debug_Printf(const char* format, ...)
{ {
va_list args; va_list args;
@@ -85,7 +89,9 @@ void Debug_Printf(const char* format, ...)
#else #else
// 调试关闭时,提供空实现 // 调试关闭时,提供空实现
/* 函数作用:调试关闭时提供空初始化函数,保持接口兼容。 */
void Debug_Init(void) {} void Debug_Init(void) {}
/* 函数作用:调试关闭时丢弃格式化输出,保持接口兼容。 */
void Debug_Printf(const char* format, ...) {} void Debug_Printf(const char* format, ...) {}
#endif #endif
+2
View File
@@ -8,9 +8,11 @@
#define DEBUG_ENABLE 1 // 暂时关闭,添加Debug.c后改回1 #define DEBUG_ENABLE 1 // 暂时关闭,添加Debug.c后改回1
// 调试串口初始化(使用USART2,PA2/PA3) // 调试串口初始化(使用USART2,PA2/PA3)
// 函数作用:初始化调试串口 USART2,供 DEBUG_PRINT 输出日志使用。
void Debug_Init(void); void Debug_Init(void);
// 调试信息输出函数 // 调试信息输出函数
// 函数作用:按 printf 格式输出调试日志到调试串口。
void Debug_Printf(const char* format, ...); void Debug_Printf(const char* format, ...);
// 快捷宏定义 // 快捷宏定义
+5
View File
@@ -8,6 +8,7 @@ volatile uint32_t g_time_ms = 0;
/** /**
* @brief 初始化SysTick定时器,配置为1ms中断一次 * @brief 初始化SysTick定时器,配置为1ms中断一次
*/ */
/* 函数作用:初始化 SysTick,使系统每 1ms 进入一次中断。 */
void Delay_Init(void) void Delay_Init(void)
{ {
// 配置SysTick为1ms中断一次。SystemCoreClock通常是72MHz。 // 配置SysTick为1ms中断一次。SystemCoreClock通常是72MHz。
@@ -22,6 +23,7 @@ void Delay_Init(void)
* @brief 获取自启动以来的毫秒数 * @brief 获取自启动以来的毫秒数
* @retval 当前的毫秒时间戳 * @retval 当前的毫秒时间戳
*/ */
/* 函数作用:返回系统启动以来累计的毫秒计数。 */
uint32_t Get_Time_ms(void) uint32_t Get_Time_ms(void)
{ {
return g_time_ms; return g_time_ms;
@@ -30,6 +32,7 @@ uint32_t Get_Time_ms(void)
// --- 以下是你原本就有的阻塞式延时函数,保持不变 --- // --- 以下是你原本就有的阻塞式延时函数,保持不变 ---
/* 函数作用:使用 SysTick 实现微秒级阻塞延时。 */
void Delay_us(uint32_t xus) void Delay_us(uint32_t xus)
{ {
SysTick->LOAD = 72 * xus; SysTick->LOAD = 72 * xus;
@@ -39,6 +42,7 @@ void Delay_us(uint32_t xus)
SysTick->CTRL = 0x00000004; SysTick->CTRL = 0x00000004;
} }
/* 函数作用:基于毫秒 tick 实现毫秒级阻塞延时。 */
void Delay_ms(uint32_t xms) void Delay_ms(uint32_t xms)
{ {
// 使用SysTick计时器实现精确延时 // 使用SysTick计时器实现精确延时
@@ -48,6 +52,7 @@ void Delay_ms(uint32_t xms)
} }
} }
/* 函数作用:通过循环调用毫秒延时实现秒级阻塞延时。 */
void Delay_s(uint32_t xs) void Delay_s(uint32_t xs)
{ {
while(xs--) while(xs--)
+5
View File
@@ -5,12 +5,17 @@
#include "stm32f10x.h" // 确保包含了这个 #include "stm32f10x.h" // 确保包含了这个
// 添加下面两个函数的声明 // 添加下面两个函数的声明
// 函数作用:初始化 SysTick 延时模块和毫秒计时基准。
void Delay_Init(void); void Delay_Init(void);
// 函数作用:返回系统启动以来经过的毫秒数。
uint32_t Get_Time_ms(void); uint32_t Get_Time_ms(void);
// 保留你原有的函数声明 // 保留你原有的函数声明
// 函数作用:阻塞延时指定微秒数。
void Delay_us(uint32_t us); void Delay_us(uint32_t us);
// 函数作用:阻塞延时指定毫秒数。
void Delay_ms(uint32_t ms); void Delay_ms(uint32_t ms);
// 函数作用:阻塞延时指定秒数。
void Delay_s(uint32_t s); void Delay_s(uint32_t s);
#endif #endif
+18
View File
@@ -84,11 +84,13 @@ uint32_t last_process_time = 0;
#define PROCESS_INTERVAL_MS 2000 #define PROCESS_INTERVAL_MS 2000
/* --- 辅助函数 --- */ /* --- 辅助函数 --- */
/* 函数作用:判断指定年份是否为闰年。 */
static uint8_t IsLeapYear(uint16_t year) static uint8_t IsLeapYear(uint16_t year)
{ {
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0; return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0;
} }
/* 函数作用:返回指定年份和月份对应的天数。 */
static uint8_t DaysInMonth(uint16_t year, uint8_t month) static uint8_t DaysInMonth(uint16_t year, uint8_t month)
{ {
static const uint8_t days_table[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; static const uint8_t days_table[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
@@ -97,6 +99,7 @@ static uint8_t DaysInMonth(uint16_t year, uint8_t month)
return days_table[month - 1]; return days_table[month - 1];
} }
/* 函数作用:在没有 DS1302 可用时,用系统 tick 推进软件时钟一秒。 */
static void AdvanceSoftwareClockOneSecond(void) static void AdvanceSoftwareClockOneSecond(void)
{ {
g_current_time.second++; g_current_time.second++;
@@ -122,6 +125,7 @@ static void AdvanceSoftwareClockOneSecond(void)
g_current_time.year++; g_current_time.year++;
} }
/* 函数作用:启动签到成功提示音和成功指示灯。 */
void StartBeepSuccess(void) void StartBeepSuccess(void)
{ {
BUZZER_OFF(); BUZZER_OFF();
@@ -133,6 +137,7 @@ void StartBeepSuccess(void)
LED_SUCCESS_ON(); LED_SUCCESS_ON();
} }
/* 函数作用:启动重复签到提示音和指示灯闪烁序列。 */
void StartBeepDuplicate(void) void StartBeepDuplicate(void)
{ {
BUZZER_OFF(); BUZZER_OFF();
@@ -144,6 +149,7 @@ void StartBeepDuplicate(void)
LED_SUCCESS_ON(); LED_SUCCESS_ON();
} }
/* 函数作用:在主循环中推进蜂鸣器和指示灯的非阻塞提示状态。 */
void ProcessBeep(void) void ProcessBeep(void)
{ {
if (beep_state == BEEP_IDLE) { if (beep_state == BEEP_IDLE) {
@@ -185,6 +191,7 @@ void ProcessBeep(void)
} }
} }
/* 函数作用:刷新空闲状态下 OLED 显示的系统状态和待同步数量。 */
void UpdateIdleScreen(void) void UpdateIdleScreen(void)
{ {
OLED_Clear(); OLED_Clear();
@@ -203,6 +210,7 @@ void UpdateIdleScreen(void)
/** /**
* @brief 发送加密的考勤记录到服务器(新版本) * @brief 发送加密的考勤记录到服务器(新版本)
*/ */
/* 函数作用:将一条考勤记录组装为 JSON,加密后通过 ESP8266 上传服务器。 */
uint8_t SendEncryptedAttendance(AttendanceRecord* record) uint8_t SendEncryptedAttendance(AttendanceRecord* record)
{ {
char json_data[256]; char json_data[256];
@@ -244,6 +252,7 @@ uint8_t SendEncryptedAttendance(AttendanceRecord* record)
} }
} }
/* 函数作用:批量同步本地待上传考勤记录,并根据结果更新同步状态。 */
void SyncPendingRecords(void) void SyncPendingRecords(void)
{ {
uint32_t current_time = Get_Time_ms(); uint32_t current_time = Get_Time_ms();
@@ -312,6 +321,7 @@ void SyncPendingRecords(void)
synced_count, failed_count); synced_count, failed_count);
} }
/* 函数作用:从服务器同步网络时间,并在 DS1302 可用时写入 RTC。 */
uint8_t SyncNetworkTime(void) uint8_t SyncNetworkTime(void)
{ {
DEBUG_INFO("Syncing time from network..."); DEBUG_INFO("Syncing time from network...");
@@ -376,6 +386,7 @@ uint8_t SyncNetworkTime(void)
return 0; return 0;
} }
/* 函数作用:从同步状态 JSON 中提取服务端版本号。 */
static uint32_t ParseSyncVersion(const char* json) static uint32_t ParseSyncVersion(const char* json)
{ {
const char* p; const char* p;
@@ -395,6 +406,7 @@ static uint32_t ParseSyncVersion(const char* json)
return version; return version;
} }
/* 函数作用:从服务端下载 STM32 需要的同步状态并更新时间段配置。 */
uint8_t DownloadTimeSlots(void) uint8_t DownloadTimeSlots(void)
{ {
char response_buffer[768]; char response_buffer[768];
@@ -444,6 +456,7 @@ uint8_t DownloadTimeSlots(void)
return 0; return 0;
} }
/* 函数作用:按固定间隔自动从服务端刷新时间段配置。 */
void UpdateTimeSlotConfig(void) void UpdateTimeSlotConfig(void)
{ {
uint32_t current_time = Get_Time_ms(); uint32_t current_time = Get_Time_ms();
@@ -471,6 +484,7 @@ void UpdateTimeSlotConfig(void)
} }
} }
/* 函数作用:更新当前时间来源,优先读取 DS1302,失败时使用软件时钟并定期 NTP 校时。 */
void UpdateCurrentTime(void) void UpdateCurrentTime(void)
{ {
uint32_t current_ms = Get_Time_ms(); uint32_t current_ms = Get_Time_ms();
@@ -530,6 +544,7 @@ void UpdateCurrentTime(void)
} }
} }
/* 函数作用:按重连间隔尝试恢复 WiFi,并在成功后连接 HTTP 服务器和同步配置。 */
uint8_t TryReconnectWiFi(void) uint8_t TryReconnectWiFi(void)
{ {
uint32_t current_time = Get_Time_ms(); uint32_t current_time = Get_Time_ms();
@@ -585,6 +600,7 @@ uint8_t TryReconnectWiFi(void)
return 0; return 0;
} }
/* 函数作用:按重连间隔尝试恢复 HTTP 服务器连接。 */
uint8_t TryReconnectServer(void) uint8_t TryReconnectServer(void)
{ {
uint32_t current_time = Get_Time_ms(); uint32_t current_time = Get_Time_ms();
@@ -616,6 +632,7 @@ uint8_t TryReconnectServer(void)
return 0; return 0;
} }
/* 函数作用:周期性检查服务器连接状态,断线时触发自动重连。 */
void CheckServerConnection(void) void CheckServerConnection(void)
{ {
uint32_t current_time = Get_Time_ms(); uint32_t current_time = Get_Time_ms();
@@ -653,6 +670,7 @@ void CheckServerConnection(void)
// ====================================================================== // ======================================================================
// 主函数 // 主函数
// ====================================================================== // ======================================================================
/* 函数作用:STM32 固件入口,完成硬件初始化并循环处理识别、考勤、联网和显示任务。 */
int main(void) int main(void)
{ {
AttendanceStatus att_status; AttendanceStatus att_status;
+1
View File
@@ -67,6 +67,7 @@
*/ */
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */ /* Exported functions ------------------------------------------------------- */
/* 函数作用:在开启断言检查时报告参数断言失败所在的文件和行号。 */
void assert_failed(uint8_t* file, uint32_t line); void assert_failed(uint8_t* file, uint32_t line);
#else #else
#define assert_param(expr) ((void)0) #define assert_param(expr) ((void)0)
+2
View File
@@ -13,6 +13,7 @@ extern volatile uint32_t g_time_ms;
* @brief SysTick中断处理函数(1ms中断一次) * @brief SysTick中断处理函数(1ms中断一次)
* @note 用于维护系统时间戳和延时功能 * @note 用于维护系统时间戳和延时功能
*/ */
/* 函数作用:每 1ms 递增系统毫秒计数,为延时和定时任务提供时间基准。 */
void SysTick_Handler(void) void SysTick_Handler(void)
{ {
g_time_ms++; // 每1ms递增一次 g_time_ms++; // 每1ms递增一次
@@ -21,6 +22,7 @@ void SysTick_Handler(void)
//... HardFault_Handler 等其他中断保持不变 ... //... HardFault_Handler 等其他中断保持不变 ...
// USART3中断(来自K210,根据连接图.md: K210使用USART3 PB10/PB11) // USART3中断(来自K210,根据连接图.md: K210使用USART3 PB10/PB11)
/* 函数作用:接收 K210 串口发送的人脸识别结果,并按换行符组帧。 */
void USART3_IRQHandler(void) void USART3_IRQHandler(void)
{ {
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET) if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
+11
View File
@@ -21,18 +21,29 @@
/* Exported functions ------------------------------------------------------- */ /* Exported functions ------------------------------------------------------- */
/* 函数作用:处理不可屏蔽中断,当前项目中保留默认异常入口。 */
void NMI_Handler(void); void NMI_Handler(void);
/* 函数作用:处理硬件错误异常,进入错误保护循环便于定位严重故障。 */
void HardFault_Handler(void); void HardFault_Handler(void);
/* 函数作用:处理内存管理异常,当前项目中保留默认异常入口。 */
void MemManage_Handler(void); void MemManage_Handler(void);
/* 函数作用:处理总线错误异常,当前项目中保留默认异常入口。 */
void BusFault_Handler(void); void BusFault_Handler(void);
/* 函数作用:处理未定义指令等用法错误异常,当前项目中保留默认异常入口。 */
void UsageFault_Handler(void); void UsageFault_Handler(void);
/* 函数作用:处理系统服务调用异常,当前项目中保留默认异常入口。 */
void SVC_Handler(void); void SVC_Handler(void);
/* 函数作用:处理调试监视异常,当前项目中保留默认异常入口。 */
void DebugMon_Handler(void); void DebugMon_Handler(void);
/* 函数作用:处理可挂起系统服务异常,当前项目中保留默认异常入口。 */
void PendSV_Handler(void); void PendSV_Handler(void);
/* 函数作用:处理系统滴答定时器中断,用于毫秒计时和延时基准。 */
void SysTick_Handler(void); void SysTick_Handler(void);
// 外设中断 // 外设中断
/* 函数作用:处理 USART1 中断,用于 ESP8266 串口通信接收。 */
void USART1_IRQHandler(void); void USART1_IRQHandler(void);
/* 函数作用:处理 USART3 中断,用于 K210 人脸识别结果接收。 */
void USART3_IRQHandler(void); void USART3_IRQHandler(void);
#ifdef __cplusplus #ifdef __cplusplus