需求(2026-09-10): 打通 vd960DBN 与 vd960Air(Air780) 两侧串口对接逻辑 ——
DBN 侧 UART1(PB6/PB7) 通道 + UART2↔UART1 双向透传。
协议依据 DLD960_IoT_MQTT协议 §6.1(V1.12 方案C):
上行 Loop 0x7F(UART2) --原样转发--> UART1 --> Air780 解析转 JSON --> MQTT
下行 平台 JSON --> Air780 --转 0x7F 帧--> DBN --0x7F(UART2)--> Loop
DBN 只做字节流透传, 零业务转换; 魔数分流: 0x7F -> UART2, 0x8F -> DBN 本地
实现:
- usart_biz.c +242 行: UART1 通道整段
* uart1_dma_init(): USART1 重映射 PB6(TX)/PB7(RX), 115200 8N1,
RX 走 DMA1_Ch5 循环 512B (UART2 占 Ch6/Ch7, 不冲突)
* uart1_feed_byte()/uart1_frame_ready()/uart1_resync(): 独立帧装配器
* uart1_dispatch_frame(): 按魔数分流
* uart1_dma_poll(): 主循环消费 DMA 缓冲
* uart_srv() 内插入上行转发(484-490): 紧接 lup_process_frame 之后、
InitPkgUart 消费之前, 且只转发 lup_verify_checksum()==0 的完整帧
(位置必须在 BLE 分支改写 pkg[0]=0x8F 之前, 否则会给 Air780 发错魔数帧)
- cmcng.h: 声明 uart1_dma_init/poll + 5 个通道计数
- peripheral_main.c: 主循环加 uart1_dma_poll() (置于 MK_UART_SRV fault marker
之外, 不改变既有 marker 语义)
三个关键决定:
1. 接收走 DMA 而非 RXNE 中断 —— 理由同 UART2 方案A(2026-08-17): PRINT 临界区
关中断 ~7.4ms / BLE 栈回调 / SPI 擦除 45ms 等长阻塞窗口会屏蔽 RXNE 丢字节。
"不丢帧"是 Air780 沿检测(loop_state 变化沿)判车的硬前提。
2. 帧装配器独立于 g_lup_parser —— 后者硬编码专供 UART2/Loop 通道, 两条流混进
同一状态机必然互相残杀; 只复用纯函数 lup_verify_checksum()。
3. 坏帧回找魔数 resync —— 防"单帧损坏 → 后续帧全部失步、链路长时间瞎掉"。
与 printf 共用 USART1 (按用户 2026-09-10 指示: printf 串口不动, 4G 时禁用 debug):
- 开关 UART1_AIR780_EN, 默认 (DEBUG == 0)
- 4G 版本 -DDEBUG=0 编译即自动启用: #if(DEBUG) 为假 -> PRINT 空宏, 且
USART_Printf_Init() 里 USART1 配置分支整段不编译(已核对 USART_Init/USART_Cmd
均在 #if(DEBUG == DEBUG_UART1) 内)
- 调试版本通道为空实现; debug.h/debug.c 一行未改, printf 行为完全不变
验证:
- host 单测: 从 usart_biz.c 原样抽取装配器 + 逐字复刻 loop_uart_proto.c 的
XOR/SUM 校验, gcc -Wall -Wextra -Werror 零警告, 13 组用例全部通过 ——
含"坏帧后紧跟好帧仍送达"、"截断帧后只交付 1 帧完整好帧"、70B 最大帧、
LEN 非法/超长、0x9F(Loop OTA 魔数)忽略、上行闸门只放行校验通过帧
- 待板级验证: 本机无 RISC-V 工具链, 固件编译与实机联调尚未进行
现场核对: 新增 g_uart1_fwd_to_air / _to_loop / _local_cnt / _badchk / _drop
计数, 判据为"g_uart1_fwd_to_air 与 Air780 侧实收帧数相等"
文档: devlog 新增 2026-09-10 条目(含接线说明 PB6/PB7 交叉 + 待办清单)
446 lines
15 KiB
C
446 lines
15 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
||
* File Name : main.c
|
||
* Author : WCH
|
||
* Version : V1.1
|
||
* Date : 2020/08/06
|
||
* Description : Peripheral slave application main function and task system initialization
|
||
*********************************************************************************
|
||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||
* Attention: This software (modified or not) and binary are used for
|
||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||
*******************************************************************************/
|
||
|
||
/******************************************************************************/
|
||
/* Header file contains */
|
||
#include "CONFIG.h"
|
||
#include "HAL.h"
|
||
#include "gattprofile.h"
|
||
#include "peripheral.h"
|
||
#include "cmcng.h"
|
||
#include <string.h>
|
||
#include "dbn_ble_srv.h"
|
||
#include "eth_driver.h"
|
||
#include "net_srv.h"
|
||
#include "storage.h"
|
||
#include "offlog.h"
|
||
#include "snapshot.h"
|
||
#include "tcp_json_srv.h"
|
||
#include "loop_uart_proto.h"
|
||
#include "iot_mqtt_srv.h"
|
||
#include "ota_srv.h"
|
||
#include "fault_diag.h"
|
||
|
||
/*********************************************************************
|
||
* GLOBAL TYPEDEFS
|
||
*/
|
||
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
|
||
|
||
#define KEY_GPIO (RCC_APB2Periph_GPIOA)
|
||
#define KEY_BV BV(0)
|
||
#define KEY_IN (GPIO_ReadInputDataBit(KEY_GPIO, KEY_BV)==0)
|
||
#define HAL_PUSH_BUTTON() (KEY1_IN) //Add custom button
|
||
|
||
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
|
||
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
||
// #else
|
||
// uint8_t MACAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
||
#endif
|
||
uint8_t gMacAddr[6] = { 0x38, 0x3B, 0x26, 0x11, 0xA4 ,0x35 };
|
||
|
||
/* Used for app judgment file effectiveness */
|
||
const uint32_t Address = 0xFFFFFFFF;
|
||
|
||
__attribute__((aligned(4))) uint32_t Image_Flag __attribute__((section(".ImageFlag"))) = (uint32_t)&Address;
|
||
|
||
uint8_t g_dev_number[6] = ""; // �豸��� ��Ʒ���
|
||
uint8_t g_dev_password[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36};
|
||
uint8_t g_ble_safe_flag = 0;
|
||
uint32_t g_ble_safe_counter_ori = 0;
|
||
uint32_t g_ble_safe_counter_dst = 0;
|
||
|
||
char g_flag_debug = 1;
|
||
|
||
uint8_t g_dg_device_type = DDType_DLD950V4; // ???����?????????????
|
||
uint8_t g_dg_sub_dev_type = DDType_DLD950V4;
|
||
|
||
Sub_Code_Enable g_sub_code_enable = {0,};
|
||
|
||
uint32_t g_activ_counter = 0;
|
||
|
||
uint32_t g_counter_bt_timeout = 0;
|
||
uint8_t g_flag_bt_state = 0;
|
||
uint8_t g_flag_bt_disable = 0;
|
||
|
||
uint8_t g_max_counter_bt_min = 0;
|
||
uint32_t g_max_counter_bt_timeout = 0; //BT_DISABLE_IDLE_TIMEOUT * 60 * 1000; // ms unit
|
||
|
||
|
||
__IO uint32_t TimingDelayInc;
|
||
__IO uint32_t TimingDelayDec;
|
||
|
||
uint8_t trigB;
|
||
Pkg_Uart g_pkg_uart_1 = { 0, 0, 0, "", 0};
|
||
Pkg_Uart g_pkg_uart_2 = { 0, 0, 0, "", 0};
|
||
|
||
Flag_Counter g_flag_counter_key = {0, 0, 0};
|
||
Flag_Counter g_flag_counter_ota = {0, 0, 0};
|
||
|
||
uint8_t g_storage_uart_num = 0;
|
||
uint32_t g_storage_uart_baud = 19200;//9600;
|
||
uint8_t g_storage_uart_num_2 = 1;
|
||
uint32_t g_storage_uart_baud_2 = 115200; //115200;
|
||
|
||
uint32_t mstick(void){
|
||
return TimingDelayInc;
|
||
}
|
||
|
||
|
||
void InitPkgUart(Pkg_Uart * pkg){
|
||
memset(pkg->pkg, 0, BUFF_STACK_SIZE);
|
||
pkg->flag = 0;
|
||
pkg->tick = 0;
|
||
pkg->len = 0;
|
||
pkg->offset = 0;
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************
|
||
* @fn TIM2_Init
|
||
*
|
||
* @brief Initializes TIM2.
|
||
*
|
||
* @return none
|
||
*/
|
||
void TIM2_Init( void )
|
||
{
|
||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure={0};
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
||
|
||
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
||
TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1;
|
||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
|
||
TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);
|
||
|
||
TIM_Cmd(TIM2, ENABLE);
|
||
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
|
||
NVIC_EnableIRQ(TIM2_IRQn);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn TIM3_Init
|
||
*
|
||
* @brief Initializes TIM3.
|
||
*
|
||
* @return none
|
||
*/
|
||
void TIM3_Init(void)
|
||
{
|
||
NVIC_InitTypeDef NVIC_InitStructure={0};
|
||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = { 0 };
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||
|
||
////10ms
|
||
// TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
||
// TIM_TimeBaseStructure.TIM_Prescaler = 10 * 1000 - 1;
|
||
|
||
//1ms
|
||
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
||
TIM_TimeBaseStructure.TIM_Prescaler = 1 * 1000 - 1;
|
||
|
||
|
||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
|
||
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
|
||
|
||
TIM_Cmd(TIM3, ENABLE);
|
||
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||
NVIC_EnableIRQ(TIM3_IRQn);
|
||
}
|
||
|
||
|
||
void key_event_srv(void){
|
||
// if(g_flag_counter_key.tick > 1000){
|
||
// PRINT("key_tick_timeup_______: %d\n", GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));
|
||
// g_flag_counter_key.tick = 0;
|
||
// }
|
||
if(g_flag_counter_key.flag){
|
||
uint8_t _pkg[7] = {0};
|
||
uint8_t i = 0;
|
||
switch (g_flag_counter_key.flag) {
|
||
case KEY_ET_BLE_ENABLE: {
|
||
PRINT("______KEY_ET_BLE_ENABLE\n");
|
||
NVIC_SystemReset();
|
||
} break;
|
||
case KEY_ET_REBOOT: {
|
||
PRINT("__________KEY_ET_REBOOT\n");
|
||
_pkg[i++] = 0x7F;
|
||
_pkg[i++] = 0x00;
|
||
_pkg[i++] = 0x01;
|
||
_pkg[i++] = 0x6D;
|
||
_pkg[i++] = 0x6C;
|
||
_pkg[i++] = 0x6E;
|
||
UART2_SendString(_pkg, i); //1 send loop mcu reboot;
|
||
|
||
Delay_Ms(10);
|
||
// 2 DBN dev reboot
|
||
NVIC_SystemReset();
|
||
} break;
|
||
case KEY_ET_FACTORY: {
|
||
PRINT("_____________KEY_ET_FACTORY\n");
|
||
_pkg[i++] = 0x7F;
|
||
_pkg[i++] = 0x00;
|
||
_pkg[i++] = 0x01;
|
||
_pkg[i++] = 0x92;
|
||
_pkg[i++] = 0x93;
|
||
_pkg[i++] = 0x93;
|
||
UART2_SendString(_pkg, i); //1 send loop mcu factory init
|
||
|
||
|
||
} break;
|
||
case KEY_ET_NETBLE_FACTORY: {
|
||
//2 DBN dev factory init;
|
||
factory_dev_info();
|
||
Delay_Ms(10);
|
||
|
||
NVIC_SystemReset();
|
||
} break;
|
||
|
||
}
|
||
g_flag_counter_key.flag = 0;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
/*********************************************************************
|
||
* @fn Main_Circulation
|
||
*
|
||
* @brief Main loop
|
||
*
|
||
* @return none
|
||
*/
|
||
__attribute__((section(".highcode")))
|
||
__attribute__((noinline))
|
||
void Main_Circulation(void)
|
||
{
|
||
uint32_t _counter = 0;
|
||
while(1)
|
||
{
|
||
FAULT_MARKER(MK_LOOP_TOP);
|
||
iot_watchdog_kick(); /* 无条件喂狗 (2026-08-13): 原只在 iot_mqtt_poll, tcp_json 分支不喂 */
|
||
snap_delayed_init(); /* 快照区延后初始化: 开机 3s 后首次进入执行 (2026-08-17) */
|
||
TMOS_SystemProcess();
|
||
|
||
if(g_net_state.flag < 2)
|
||
{
|
||
net_srv_init();
|
||
}
|
||
if(g_net_state.flag == 2)
|
||
{
|
||
if(g_sub_code_enable.iot_enable){
|
||
if(iot_net_info.mode == IOT_Addr_IP_Mode){
|
||
if(get_ipstr_to_array(iot_net_info.remote_addr, RemoteIP) == 0){
|
||
WCHNET_CreateTcpMqttSocket();
|
||
}
|
||
}
|
||
else{
|
||
//DNS
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
WCHNET_CreateTcpSocket();
|
||
}
|
||
}
|
||
|
||
|
||
/*Ethernet library main task function,
|
||
* which needs to be called cyclically*/
|
||
WCHNET_MainTask();
|
||
/*Query the Ethernet global interrupt,
|
||
* if there is an interrupt, call the global interrupt handler*/
|
||
if(WCHNET_QueryGlobalInt())
|
||
{
|
||
WCHNET_HandleGlobalInt();
|
||
}
|
||
|
||
FAULT_MARKER(MK_UART_SRV_IN);
|
||
uart_srv();
|
||
FAULT_MARKER(MK_UART_SRV_OUT);
|
||
uart1_dma_poll(); /* 4G 通道下行收帧 (协议 §6.1): 置于 fault marker 之外, 不改变 MK_UART_SRV 语义 */
|
||
ota_poll(); /* OTA 刷写状态机 (V1.08): 非阻塞 tick 驱动, 先消费 UART2 ACK 再推进 */
|
||
snap_flush(); /* 快照落盘: 无条件挂主循环 (原在 iot_enable 分支, TCP 模式不落盘) */
|
||
FAULT_MARKER(MK_POLL_BLE_IN);
|
||
poll_dbn_ble();
|
||
|
||
if (g_sub_code_enable.iot_enable) {
|
||
iot_mqtt_publish_sensor(); // Push 0xC0 sensor data to MQTT broker
|
||
iot_mqtt_poll(); // IoT MQTT state machine + PINGREQ keepalive
|
||
} else {
|
||
tcp_json_push_sensor(); // Push 0xC0 sensor data to TCP JSON client
|
||
tcp_json_poll();
|
||
}
|
||
|
||
key_event_srv();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************
|
||
* @fn main
|
||
*
|
||
* @brief Main function
|
||
*
|
||
* @return none
|
||
*/
|
||
int main(void)
|
||
{
|
||
SystemCoreClockUpdate();
|
||
Delay_Init();
|
||
#ifdef DEBUG
|
||
// USART_Printf_Init( 115200 );
|
||
USART_Printf_Init( 256000 );
|
||
#endif
|
||
/* 诊断: 复位原因寄存器 (bit31=IWDG bit30=WWDG bit29=LPWR bit26=NRST bit25=POR bit24=软复位)
|
||
每次上电必打, 区分看门狗死锁 vs 掉电 vs 外部复位 */
|
||
PRINT("RST_REASON: 0x%08lx\n", (unsigned long)OFFLOG_RCC_RSTSCKR);
|
||
fault_diag_init(); /* 打印上次复位现场 (HardFault mcause/mepc + 执行轨迹 marker) */
|
||
iot_watchdog_init(); /* 无条件 IWDG (2026-08-13): iot_enable=0 时 iot_mqtt_init 不调,
|
||
卡死无兜底 → 永久冻结。IWDG 4s 超时 + 主循环喂狗 */
|
||
PRINT("%s\n", VER_LIB);
|
||
PRINT("SystemCoreClock:%d\n", SystemCoreClock);
|
||
/* ===== 实验: 禁用全部 Flash/SPI 操作 (2026-08-12) =====
|
||
结论: 禁用后设备稳定 → SPI 操作触发复位+乱码实锤
|
||
软件缓解: storage.c SPI 时钟降档 + GPIO 缓边沿 (见 SPI_Flash_Init)
|
||
硬件根治: NRST 加 100nF 电容 / SPI 走线远离 NRST / 串阻缓边沿
|
||
#if 0 = 恢复全部 SPI; 保留本块便于回退实验 */
|
||
#if 0
|
||
PRINT("ISOLATE: flash/SPI disabled (flash isolation test)\n");
|
||
#else
|
||
GetMacAddr(gMacAddr);
|
||
storage_init();
|
||
PRINT("INIT: storage ok\n");
|
||
offlog_init();
|
||
PRINT("INIT: offlog ok\n");
|
||
ota_init(); /* OTA 元数据恢复 (V1.08): 下载中断续传 / 刷写中断标记失败 */
|
||
PRINT("INIT: ota ok\n");
|
||
/* 快照区: 延后初始化 (2026-08-17) — snap_init 移到主循环 3s 后
|
||
(snap_delayed_init), 避开启动早期 SPI 重负载窗口 (擦+整扇区写回 ~80ms);
|
||
3s 内的传感帧由 snap_enqueue/snap_flush 的 !_ready 门控自动丢弃不落盘 */
|
||
|
||
/* offlog_boot: 记录本次复位原因到事件日志。
|
||
实验A(2026-08-17, 跳过offlog_boot仍崩)证明其非跑飞触发点 → 已恢复 */
|
||
{
|
||
uint32_t rcc_rst = OFFLOG_RCC_RSTSCKR;
|
||
offlog_boot(rcc_rst);
|
||
OFFLOG_RCC_RSTSCKR |= OFFLOG_RST_RMVF; /* RMVF (bit24): 清复位标志 */
|
||
}
|
||
|
||
/* ===== 栈溢出修复闭环 (2026-08-17) =====
|
||
根因: .bss≈46KB → 栈仅~1.9KB; load_cfg/output_cfg 的 printf 栈峰值触顶
|
||
→ 覆盖 .noinit+返回地址 → PC 跑飞循环。
|
||
修复: ①实验D定位触发点 ②RAM 瘦身 (ETH 768/payload 800/MQTT buf 800,
|
||
栈 1.9KB→~4.75KB) ③load_cfg 字符串 0 终止保险 ④打印恢复。 */
|
||
load_cfg_from_flash();
|
||
output_cfg_from_flash(); /* 2026-08-17: 栈瘦身后恢复 (栈~4.75KB, printf 峰值安全) */
|
||
#endif
|
||
|
||
PRINT("MAC: %02X %02X %02X %02X %02X %02X\r\n", gMacAddr[0],gMacAddr[1], gMacAddr[2], gMacAddr[3],gMacAddr[4],gMacAddr[5]);
|
||
PRINT("net version:%x\n", WCHNET_GetVer());
|
||
WCHBLE_Init();
|
||
HAL_Init();
|
||
|
||
uart_init();
|
||
|
||
/* ===== 实验: 禁用 UART2 (Loop 口) 隔离测试 (2026-08-12) =====
|
||
结论: UART2 禁用后仍复位 → 与 Loop 数据路径无关 (后定位为 SPI 串扰)
|
||
#if 0 = 恢复 UART2 正常 */
|
||
#if 0
|
||
{
|
||
GPIO_InitTypeDef gpio;
|
||
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
|
||
USART_Cmd(USART2, DISABLE);
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||
gpio.GPIO_Pin = GPIO_Pin_3;
|
||
gpio.GPIO_Mode = GPIO_Mode_IPU; /* PA3 脱离 UART2, 上拉输入 */
|
||
gpio.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_Init(GPIOA, &gpio);
|
||
PRINT("ISOLATE: UART2 disabled (Loop isolation test)\n");
|
||
}
|
||
#endif
|
||
|
||
TIM3_Init();
|
||
TIM2_Init();
|
||
|
||
GAPRole_PeripheralInit();
|
||
Peripheral_Init();
|
||
Main_Circulation();
|
||
}
|
||
|
||
|
||
void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||
/*********************************************************************
|
||
* @fn TIM3_IRQHandler, 1ms
|
||
*
|
||
* @brief This function handles TIM2 exception.
|
||
*
|
||
* @return none
|
||
*/
|
||
void TIM3_IRQHandler(void)
|
||
{
|
||
TimingDelayInc++;
|
||
g_activ_counter++;
|
||
|
||
if(g_pkg_uart_2.offset){
|
||
if(g_pkg_uart_2.flag == 0){
|
||
g_pkg_uart_2.tick++;
|
||
if(g_pkg_uart_2.tick > 8){
|
||
g_pkg_uart_2.flag = 1;
|
||
}
|
||
}
|
||
}
|
||
// Safety: reset frame parser if stuck in non-IDLE state too long
|
||
if(g_lup_parser.state != LUP_FRAME_STATE_IDLE){
|
||
if(g_pkg_uart_2.tick > 20){
|
||
lup_frame_reset();
|
||
g_pkg_uart_2.tick = 0;
|
||
}
|
||
}
|
||
|
||
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0){//HAL_PUSH_BUTTON()){
|
||
g_flag_counter_key.tick++;
|
||
}
|
||
else{
|
||
if(g_flag_counter_key.tick){
|
||
if(g_flag_counter_key.tick < 2000){
|
||
g_flag_counter_key.flag = KEY_ET_BLE_ENABLE;
|
||
}
|
||
else if(g_flag_counter_key.tick < 6000){
|
||
g_flag_counter_key.flag = KEY_ET_REBOOT;
|
||
}
|
||
else if(g_flag_counter_key.tick < 10000){
|
||
g_flag_counter_key.flag = KEY_ET_FACTORY;
|
||
}
|
||
else{
|
||
g_flag_counter_key.flag = KEY_ET_NETBLE_FACTORY;
|
||
}
|
||
g_flag_counter_key.tick = 0;
|
||
}
|
||
}
|
||
|
||
|
||
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||
}
|
||
|
||
|
||
/******************************** endfile @ main ******************************/
|