91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【CW32無線抄表項目】示例通信程序講解

CW32生態(tài)社區(qū) ? 來源:CW32生態(tài)社區(qū) ? 作者:CW32生態(tài)社區(qū) ? 2026-03-31 21:16 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一、整體功能概述

這套程序模擬了一個真實的無線傳感器網(wǎng)絡(luò)(如抄表系統(tǒng))的通信流程:

  1. 主機(Master / 采集端): 負責(zé)發(fā)起通信。它首先發(fā)送“暗號”(kunkun)尋找從機,收到從機的確認(zhiyin)后,采集自身的 ADC 電壓數(shù)據(jù),將其轉(zhuǎn)換并打包發(fā)送給從機。最后,它會等待從機將收到的數(shù)據(jù)原樣發(fā)回,以驗證通信鏈路的絕對可靠性。
  2. 從機(Slave / 接收網(wǎng)關(guān)): 一直處于監(jiān)聽狀態(tài)。收到“暗號”后立刻回復(fù)確認。隨后接收主機發(fā)來的 ADC 數(shù)據(jù),并觸發(fā) LED 閃爍,最后將該數(shù)據(jù)原樣“回聲(Echo)”給主機。
int32_t main(void)
{   
    // 1. 硬件初始化
    System_Init_Config();

    // 2. 射頻初始化
    if (rf_init() != OK) 
    {
        while(1); // 失敗報警
    }
    rf_set_default_para();
    // 3. 初始狀態(tài)設(shè)置 (編譯時決定)
    #ifdef SLAVE_MODE
        // [從機] 上電必須開啟接收,否則聽不到第一句。接收超時窗口(Timeout)
        /*
        情況 A(提前下班): 如果第 2 秒鐘,主機發(fā)來了 kunkun(快遞到了),
        單片機會立刻抓起數(shù)據(jù)去處理,這個 15 秒的倒計時會瞬間作廢,根本不需要等滿 15 秒。
        情況 B(超時放棄): 如果苦苦等了整整 15 秒,主機都沒發(fā)信號(可能主機沒開機),
        從機就不會再傻等下去了。它會觸發(fā)一個“接收超時(RXTIMEOUT)”的標志位,然后重新安排下一次的監(jiān)聽。
        */
        rf_enter_single_timeout_rx(15000);

        /*
        因為在無線通信中,從機是“被動方”。它剛上電的時候,
        完全不知道主機什么時候會開口說話(主機可能 2 秒發(fā)一次,也可能 10 分鐘發(fā)一次)。
        所以,從機一開機,必須立刻把“耳朵”張開,并且給一個足夠長的時間(15 秒),
        確保在這個寬裕的時間段內(nèi),至少能“逮住”主機的一次呼叫。一旦逮住一次,雙方就建立起聯(lián)絡(luò)了。
        */
    #endif

    // [主機] 不需要預(yù)先接收,它會主動發(fā)送
    while (1)
    {
        // === 1. 優(yōu)先處理中斷 (公共邏輯) ===
        if (g_bIrqTriggered)
        {
            g_bIrqTriggered = 0;
            rf_irq_process(); // SPI 讀取狀態(tài)
        }
        // === 2. 業(yè)務(wù)邏輯 (編譯時二選一) ===
        #ifdef MASTER_MODE
            OnMaster();
        #endif
        #ifdef SLAVE_MODE
            OnSlave();
        #endif
    }
}

#ifndef __FUN_H
#define __FUN_H
// ==========================================
// 模式配置開關(guān)
// ==========================================
// 方案 A:如果是主機,保留這行,注釋掉 SLAVE_MODE
#define MASTER_MODE
// 方案 B:如果是從機,保留這行,注釋掉 MASTER_MODE
//#define SLAVE_MODE
// --- 安全檢查 (防止你忘了選,或者兩個都選了) ---
#if defined(MASTER_MODE) && defined(SLAVE_MODE)
    #error "錯誤:不能同時定義 MASTER_MODE 和 SLAVE_MODE!請注釋掉一個。"
#elif !defined(MASTER_MODE) && !defined(SLAVE_MODE)
    #error "錯誤:你沒有定義任何模式!請在 fun.h 中選擇 MASTER_MODE 或 SLAVE_MODE。"
#endif
#include "main.h"
// 函數(shù)聲明
// 這樣寫的好處是:無論什么模式,main.c 都能看到這兩個函數(shù)聲明
// 避免編譯報錯,雖然我們在 main 里只會調(diào)用其中一個
void OnSlave(void);
void LedToggle(void);
void OnMaster(void);
void Pulse_PA8(void);
uint16_t Get_ADC_Value(void);
uint16_t Get_ADC_Average(uint8_t times);
#endif

#include "fun.h"
#include "init.h"
#include "delay.h"
#include "radio.h"
#include "buffer.h"
// ============================================
// 1. 數(shù)據(jù)定義 (硬編碼 kunkun 和 zhiyin)
// ============================================
// 為了防止 buffer.c/h 未定義,我們在局部定義一份
static uint8_t Kunkun[] = {'k', 'u', 'n', 'k', 'u', 'n'};
static uint8_t Zhiyin[] = {'z', 'h', 'i', 'y', 'i', 'n'};
#define DATA_LEN 6 
// --- 補回丟失的全局變量 ---
double Rssi_dBm;   // 用于存儲最近一次接收信號的強度 (單位: dBm)
double Snr_value;  // 用于存儲最近一次接收信號的信噪比 (單位: dB)
// 外部變量聲明
extern struct RxDoneMsg RxDoneParams; 
extern uint8_t rx_test_buf[];
// ============================================
// 2. 公共函數(shù)
// ============================================
void LedToggle(void)
{
    GPIO_WritePin(LED_PORT, LED_PIN, GPIO_Pin_RESET); // 亮
//    Delay_Ms(200);
    GPIO_WritePin(LED_PORT, LED_PIN, GPIO_Pin_SET);   // 滅
//    Delay_Ms(200);
}
// ============================================
// 3. 主機模式代碼 (MASTER_MODE)
// ============================================
#ifdef MASTER_MODE
static uint32_t tx_time = 0; 
extern volatile uint8_t g_bIrqTriggered; // 引用 main.c 定義的變量
void OnMaster(void)
{
    // ==========================================
    // 階段一:握手 (Handshake)
    // 發(fā)送 "kunkun" 確認從機在線
    // ==========================================

    // 1. 發(fā)送 "kunkun"
    if (rf_single_tx_data(Kunkun, DATA_LEN, &tx_time) != OK)
    {
        return; 
    }
    // 2. 等待發(fā)送完成 (帶防死鎖的中斷處理)
    while (rf_get_transmit_flag() == RADIO_FLAG_IDLE)
    {
        if (g_bIrqTriggered) 
        { 
            g_bIrqTriggered = 0; 
            rf_irq_process(); 
        }
    }
    rf_set_transmit_flag(RADIO_FLAG_IDLE); // 清除發(fā)送標志
    // 3. 進入接收模式,等待從機回復(fù) "zhiyin"
    rf_enter_single_timeout_rx(200); 
    // 4. 等待接收完成 (帶防死鎖)
    while (rf_get_recv_flag() == RADIO_FLAG_IDLE)
    {
        if (g_bIrqTriggered) 
        { 
            g_bIrqTriggered = 0; 
            rf_irq_process(); 
        }
    }
    // ==========================================
    // 階段二:判斷握手結(jié)果 & 發(fā)送 ADC 數(shù)據(jù)
    // ==========================================

    // 檢查是否收到了數(shù)據(jù) (RXDONE)
    if (rf_get_recv_flag() == RADIO_FLAG_RXDONE)
{
    rf_set_recv_flag(RADIO_FLAG_IDLE); // 清除接收標志

    // 5. 驗證內(nèi)容是否為 "zhiyin"
    if (RxDoneParams.Size == DATA_LEN &&
        RxDoneParams.Payload[0] == 'z' && 
        RxDoneParams.Payload[1] == 'h')
    {
        // --- 握手成功!開始處理數(shù)據(jù)轉(zhuǎn)換 ---

        // A. 讀取原始 ADC 碼值 (0~4095)
        uint16_t adc_raw = Get_ADC_Average(8);

        // B. 【核心修改】轉(zhuǎn)換為十進制電壓值 (mV)
        // 公式:(adc_raw * 3300) / 4096
        // 使用 (uint32_t) 強制轉(zhuǎn)換防止乘法溢出
        uint16_t voltage_mv = (uint16_t)((uint32_t)adc_raw * 3300 / 4096);

        // C. 打包數(shù)據(jù) (將16位電壓值拆分)
        uint8_t tx_buffer[DATA_LEN];
        tx_buffer[0] = (uint8_t)(voltage_mv >> 8); // 電壓高8位
        tx_buffer[1] = (uint8_t)(voltage_mv);      // 電壓低8位

        // 填充剩余字節(jié)
        for(int k=2; k zhiyin) ===
            LedToggle(); // 提示收到握手
            Delay_Ms(5); // 避讓延時,給主機切換接收留時間

            g_bIrqTriggered = 0;
            rf_single_tx_data(Zhiyin, DATA_LEN, &sl_tx_time);
        }
        else 
        {
            // === 分支 B:數(shù)據(jù)回傳 (Echo) ===

            // [調(diào)試看這里]:此時 slave_recv_val 存儲的是十進制電壓(mV)
            // 你在調(diào)試窗口看這個變量,取消 Hex 顯示,就能看到 3200 左右的數(shù)字
            slave_recv_val = ((uint16_t)pData[0] 

二、關(guān)鍵部分代碼解析與注釋

時間線:

  1. PAN3031 芯片收發(fā)完成,拉高物理引腳。
  2. CW32 單片機被觸發(fā)物理中斷,進入 GPIOA_IRQHandler。
  3. 中斷函數(shù)火速把 g_bIrqTriggeredpan3031_irq_trigged_flag 這兩個軟件變量變成 1。
  4. 主程序 while 循環(huán)看到 g_bIrqTriggered == 1,立刻跳出等待。
  5. 主程序調(diào)用 rf_irq_process(),它看到 pan3031_irq_trigged_flag == true,準許執(zhí)行。
  6. 函數(shù)通過 SPI 查詢 PAN3031 具體原因,最終將結(jié)果翻譯成 RADIO_FLAG_RXDONE 等業(yè)務(wù)標志位。

1.ADC 數(shù)據(jù)采集與處理(主機特有)

這是示例功能——獲取的物理數(shù)據(jù)。

// ==========================================
// 階段二:判斷握手結(jié)果 & 發(fā)送 ADC 數(shù)據(jù)
// ==========================================
// 【關(guān)鍵功能 1:數(shù)據(jù)采集與轉(zhuǎn)換】
// A. 讀取原始 ADC 碼值 (0~4095)
uint16_t adc_raw = Get_ADC_Average(8);  // 多次采樣求平均,起到軟件濾波作用,抗干擾
// B. 【核心修改】轉(zhuǎn)換為十進制電壓值 (mV)
// 公式:(adc_raw * 3300) / 4096 (基于 3.3V 參考電壓)
// 使用 (uint32_t) 強制轉(zhuǎn)換防止 adc_raw * 3300 發(fā)生 16 位溢出
uint16_t voltage_mv = (uint16_t)((uint32_t)adc_raw * 3300 / 4096);
// C. 打包數(shù)據(jù) (將16位電壓值拆分成兩個 8 位字節(jié))
uint8_t tx_buffer[DATA_LEN];
tx_buffer[0] = (uint8_t)(voltage_mv >> 8); // 取電壓高 8 位放入數(shù)組第 0 個位置
tx_buffer[1] = (uint8_t)(voltage_mv);      // 取電壓低 8 位放入數(shù)組第 1 個位置

2、回聲校驗機制 (Echo Check)

這是保證通信可靠性的重要手段。

// ==========================================
// 階段三:等待回聲校驗 (Echo Check) (主機端)
// ==========================================
// F. 進入接收,等待從機把剛才的電壓值原樣發(fā)回來
rf_enter_single_timeout_rx(200);
// ... (等待接收代碼略) ...
if (rf_get_recv_flag() == RADIO_FLAG_RXDONE)
{
    rf_set_recv_flag(RADIO_FLAG_IDLE);

    // 【關(guān)鍵功能 2:數(shù)據(jù)重組與校驗】
    // 1. 將收到的兩個 8 位字節(jié)重新拼裝成 16 位的電壓數(shù)據(jù)
    uint16_t echo_val = ((uint16_t)RxDoneParams.Payload[0] 

3、從機的多路分支處理

從機需要根據(jù)收到的數(shù)據(jù)內(nèi)容,決定是進行“握手回應(yīng)”還是“數(shù)據(jù)回傳”。

// ============================================
// 4. 從機模式代碼 (SLAVE_MODE)
// ============================================
// 2. 邏輯分支判斷
// 【關(guān)鍵功能 3:協(xié)議解析】
// 檢查收到的數(shù)據(jù)長度是否為 6,且前三個字符是否為 'k' 'u' 'n'
if (len == DATA_LEN && pData[0] == 'k' && pData[1] == 'u' && pData[2] == 'n')
{
    // === 分支 A:握手協(xié)議 ===
    LedToggle(); 
    Delay_Ms(5); // 必須加!給主機從“發(fā)送態(tài)”切換到“接收態(tài)”留出時間,否則主機聽不到回信

    g_bIrqTriggered = 0;
    rf_single_tx_data(Zhiyin, DATA_LEN, &sl_tx_time); // 回復(fù)確認暗號
}
else 
{
    // === 分支 B:數(shù)據(jù)回傳 (Echo) ===
    // 解析主機發(fā)來的 16 位電壓數(shù)據(jù),主要用于在調(diào)試窗口查看
    slave_recv_val = ((uint16_t)pData[0] 

4、健壯的中斷等待機制

摒棄了官方 SDK 的“死等”,加入了基于全局變量 g_bIrqTriggered 的等待邏輯。

// 【關(guān)鍵功能 4:防死鎖等待機制】
uint32_t timeout_safety = 0; 
// 只要沒觸發(fā)中斷,且沒有超時,就在這里等
while (g_bIrqTriggered == 0 && timeout_safety < 1000000)
{
    timeout_safety++; // 軟件超時計數(shù)器,防止硬件死機導(dǎo)致程序永久卡死
}
// 退出循環(huán)后,如果是正常中斷觸發(fā),而不是超時退出的,則處理中斷
if (g_bIrqTriggered)
{
    g_bIrqTriggered = 0;
    rf_irq_process(); // 底層處理函數(shù),將狀態(tài)標志位更新為 TXDONE 或 RXDONE
}

/**
 * @brief This funcation handles GPIOA
 */
extern volatile uint8_t g_bIrqTriggered; 
void GPIOA_IRQHandler(void)
{
    // 檢查是否是 PA1 引腳觸發(fā)
    if (CW_GPIOA->ISR_f.PIN1)
    {
        // 1. 必須先清除中斷標志!
        GPIOA_INTFLAG_CLR(bv1); 
        // 2. 【核心修改】通知主循環(huán)“有事發(fā)生了”?。。?        // 只有加上這一句,OnMaster 里的 if (g_bIrqTriggered) 才會成立
        g_bIrqTriggered = 1; 
        // 3. 調(diào)用原來的業(yè)務(wù)邏輯 (保留即可)
        PAN3031_irq_handler(); 
    }
}

審核編輯 黃宇
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 通信程序
    +關(guān)注

    關(guān)注

    0

    文章

    15

    瀏覽量

    8691
  • CW32
    +關(guān)注

    關(guān)注

    1

    文章

    323

    瀏覽量

    1935
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    CW32無線表項目】主控及射頻芯片介紹

    對于開發(fā)者而言,CW32F030 的硬件設(shè)計在同類 M0+ 芯片中具有極強的競爭力。
    的頭像 發(fā)表于 04-01 17:06 ?3821次閱讀
    【<b class='flag-5'>CW32</b><b class='flag-5'>無線</b><b class='flag-5'>抄</b><b class='flag-5'>表項目</b>】主控及射頻芯片介紹

    CW32移植Free-RTOS】CW32開發(fā)者扶持計劃

    CW32配置Free-RTOS全過程,CW32開發(fā)者扶持計劃
    的頭像 發(fā)表于 04-18 09:38 ?7503次閱讀
    【<b class='flag-5'>CW32</b>移植Free-RTOS】<b class='flag-5'>CW32</b>開發(fā)者扶持計劃

    CW32快速開發(fā)入門

    CW32快速開發(fā)入門
    的頭像 發(fā)表于 04-24 18:56 ?3769次閱讀
    <b class='flag-5'>CW32</b>快速開發(fā)入門

    CW32量產(chǎn)燒錄工具

    線的程序燒錄。 燒錄器CW-Writer 一.燒錄器概況 圖1所示為燒錄器的實物展示圖。 ? 圖1 CW-Writer燒錄器 當(dāng)燒錄器通過USB口和PC機連接實現(xiàn)供電和通信功能,當(dāng)離線
    的頭像 發(fā)表于 04-25 15:22 ?2991次閱讀
    <b class='flag-5'>CW32</b>量產(chǎn)燒錄工具

    項目展示】基于CW32的遙控循跡小車

    CW32循跡小車.zip_免費高速下載|百度網(wǎng)盤-分享無限制? 一、概述 CW32循跡、遙控小車具有循跡和遙控兩種功能,小車的硬件模塊由CW32F030C8T6小藍板、智能小車控制底板、BT04-E
    的頭像 發(fā)表于 05-31 17:33 ?2597次閱讀
    【<b class='flag-5'>項目</b>展示】基于<b class='flag-5'>CW32</b>的遙控循跡小車

    CW32無線表項目】W25Q+CW32程序示例

    /Armink/SFUD 一、程序分析 硬件總線映射(引腳與時鐘的“避坑點”) ? #define FLASH_SPIx CW_SPI2// 注意:CW32 中 SPI1 在 APB2 總線,而 SPI2 通常
    的頭像 發(fā)表于 03-31 21:29 ?4212次閱讀
    【<b class='flag-5'>CW32</b><b class='flag-5'>無線</b><b class='flag-5'>抄</b><b class='flag-5'>表項目</b>】W25Q+<b class='flag-5'>CW</b>32<b class='flag-5'>程序</b><b class='flag-5'>示例</b>

    基于芯源CW32 MCU的LED閃爍示例及代碼分析

    最近我在項目中使用了芯源的CW32 MCU,這是一款非常適合物聯(lián)網(wǎng)和低功耗應(yīng)用的微控制器。在初步學(xué)習(xí)和使用中,我做了一個簡單的LED閃爍實驗,通過這篇帖子給大家分享一下代碼及相關(guān)的配置步驟。 硬件
    發(fā)表于 12-04 06:52

    CW32系列MCU在Eclipse GCC + JLink下的使用示例分享

    CW32系列MCU在Eclipse GCC + JLink下的使用示例: 1、下載安裝Eclipse IDE for Embedded C/C++ Developers。 2、下載安裝
    發(fā)表于 02-02 06:57

    【應(yīng)用筆記】CW32 自舉程序中使用的 ISP 協(xié)議

    CW32 自舉程序中使用的 ISP 協(xié)議CW32 微控制器片上 FLASH 存儲器有一部分區(qū)域用于存儲 BootLoader 啟動程序,在芯片出廠時已編程,用戶可利用 BootLoad
    發(fā)表于 06-06 13:26

    cw32和stm32的區(qū)別

    cw32和stm32的區(qū)別 CW32和STM32是兩種常見的單片機,被廣泛應(yīng)用于各種電子設(shè)備中。在本文中,我們將深入探討CW32和STM32之間的區(qū)別和優(yōu)劣勢。 1. 硬件性能 硬件性能是衡量單片機
    的頭像 發(fā)表于 08-16 11:15 ?6491次閱讀

    CW32的SPI單工模式主從通信介紹

    CW32的SPI單工模式主從通信介紹
    的頭像 發(fā)表于 10-24 15:50 ?2073次閱讀
    <b class='flag-5'>CW32</b>的SPI單工模式主從<b class='flag-5'>通信</b>介紹

    CW32定時器操作講解——輸入捕獲

    CW32定時器操作講解——輸入捕獲
    的頭像 發(fā)表于 09-27 16:06 ?2388次閱讀
    <b class='flag-5'>CW32</b>定時器操作<b class='flag-5'>講解</b>——輸入捕獲

    CW32實時時鐘(RTC)介紹

    CW32實時時鐘(RTC)介紹
    的頭像 發(fā)表于 10-24 15:36 ?2329次閱讀
    <b class='flag-5'>CW32</b>實時時鐘(RTC)介紹

    應(yīng)用筆記-CW32 自舉程序中使用的 ISP 協(xié)議

    CW32自舉程序中使用的ISP協(xié)議CW32微控制器片上FLASH存儲器有一部分區(qū)域用于存儲BootLoader啟動程序,在芯片出廠時已編程,用戶可利用BootLoader啟動
    發(fā)表于 06-06 13:37 ?7次下載

    基于CW32的物聯(lián)網(wǎng)應(yīng)用

    CW32】基于CW32的物聯(lián)網(wǎng)應(yīng)用
    的頭像 發(fā)表于 11-02 15:55 ?2064次閱讀
    基于<b class='flag-5'>CW32</b>的物聯(lián)網(wǎng)應(yīng)用