伦伦影院久久影视,天天操天天干天天射,ririsao久久精品一区 ,一本大道香蕉大久在红桃,999久久久免费精品国产色夜,色悠悠久久综合88,亚洲国产精品久久无套麻豆,亚洲香蕉毛片久久网站,一本一道久久综合狠狠老

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

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

3天內不再提示

分享一個CW32 IO拓展項目:使用CW32L010做GPIO/ADC 擴展

CW32生態社區 ? 作者:CW32生態社區 ? 2026-03-31 21:43 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1. 設計目標

CW32L010是一款極具性價比的ARM Cortex-M0+內核微控制器。其核心優勢在于以極致成本,集成了豐富的外設資源:包括一個12位精度的ADC、最多16個可配置的GPIO口以及四個通用定時器

正是基于這些特性,該芯片非常適合用于兩類核心應用場景:

功能簡單的獨立設備,如傳感器節點、小家電主控等。

作為主控系統的擴展單元,尤其是IO擴展和模擬信號采集。

當應用于IO/ADC擴展時,CW32L010不再是一顆簡單的“膠合邏輯”芯片,而是一個編程的智能外設。這意味著開發者需要為其獨立設計和燒錄固件,使其能夠按照預設的協議與主控制器進行協同工作。

本項目(固件設計)當前階段的目標,正是實現這樣一個智能擴展模塊的雛形。目前已完成的核心功能是:

基于串口(UART)的通信協議,確保與主控穩定、高效的數據交換。

完整的GPIO控制能力,支持引腳模式動態配置(輸入/輸出、上拉/下拉等)和狀態讀寫。

ADC采樣功能,可通過命令對指定通道進行模擬量采集并返回數據。

下一階段的開發路線圖已明確規劃,將重點增加以下功能:

I2C從機接口擴展:將CW32L010本身模擬為一個I2C從設備,為僅具備I2C接口的主控提供GPIO和ADC擴展能力,增加應用靈活性。

PWM輸出功能:充分利用其定時器資源,實現多通道、可調頻率與占空比的PWM信號生成,用于控制LED亮度、電機速度或生成特定波形。

2. 使用電路圖

隔離IO/ADC擴展

wKgZO2nLz4-ACWnAAACXUi9hCnw194.jpg

高端MOS控制,高端電流采樣

wKgZPGnLz5CAN751AACsmCg6JoA150.jpg

PCB

wKgZO2nLz5GAE7tQAAEtNGZ_naE636.jpg

3. 通信協議介紹

本系統通過 UART 串口(波特率 115200)控制微控制器的 GPIO 引腳,支持模式配置、狀態讀寫、ADC 采集及中斷上報功能。

3.1 支持的IO及功能

系統上電后,所有支持的 IO 默認初始化為 輸入模式

端口 (Port) 引腳 (Pin) 支持的功能 備注
Port A (0x00) PA02 輸入 / 輸出 / 中斷 / ADC (CH2)
PA03 輸入 / 輸出 / 中斷 / ADC (CH3)
PA04 輸入 / 輸出 / 中斷 / ADC (CH4)
PA05 輸入 / 輸出 / 中斷 / ADC (CH5)
PA06 輸入 / 輸出 / 中斷 / ADC (CH6)
Port B (0x01) PB00 輸入 / 輸出 / 中斷 / ADC (CH7)
PB01 輸入 / 輸出 / 中斷 / ADC (CH8)
PB02 輸入 / 輸出 / 中斷 / ADC (CH9)
PB03 輸入 / 輸出 / 中斷 / ADC (CH10)
PB04 輸入 / 輸出 / 中斷 / ADC (CH11)
PB05 輸入 / 輸出 / 中斷 / ADC (CH12)
PB06 輸入 / 輸出 / 中斷 / ADC (CH13)

注意: PA00 和 PA01 為串口通信引腳,禁止用于其他功能。

3.2串口通信協議

通信定義

波特率: 115200

數據格式: 4 字節固定長度 HEX 幀

幀結構: [命令碼] [端口] [引腳] [參數]

端口定義

0x00: Port A

0x01: Port B

引腳定義

0x00 ~ 0x0F: 對應 Pin 0 ~ Pin 15

啟動消息

設備上電或重啟完成后,會自動發送以下 HEX 序列:

HEX: 52 45 41 44 (ASCII: "READ")

3. 3 命令詳解

設置 IO 模式 (Set Mode)

發送: 01 00 02 03

接收: 01 00 02 01

發送: 01 01 00 01

接收: 01 01 00 01

參數 [Mode]:

0x00: 輸入模式 (Input) - 默認

0x01: 輸出模式 (Output Push-Pull)

0x02: 模擬模式 (Analog) - 用于 ADC

0x03: 中斷模式 (Interrupt) - 雙邊沿觸發

配置指定 IO 的工作模式。

命令碼: 0x01

格式: 01 [Port] [Pin] [Mode]

成功響應: 01 [Port] [Pin] 01

示例: 將 PB00 設置為輸出模式

示例: 將 PA02 設置為中斷模式

讀取 IO 電平 (Read Pin)

[State]: 00 (低電平) / 01 (高電平)

讀取指定 IO 當前的電平狀態。

命令碼: 0x02

格式: 02 [Port] [Pin] 00 (末尾字節無效,補0即可)

響應: 02 [Port] [Pin] [State]

示例: 讀取 PB00 電平

發送: 02 01 00 00

接收: 02 01 00 01 (當前為高電平)

3.4 設置 IO 電平 (Write Pin)

控制指定 IO 輸出高低電平(需先配置為輸出模式)。

0x00: 輸出低電平

0x01: 輸出高電平

命令碼: 0x03

格式: 03 [Port] [Pin] [Value]

參數 [Value]:

響應: 03 [Port] [Pin] 01

示例: 設置 PB00 輸出高電平

發送: 03 01 00 01

接收: 03 01 00 01

讀取 ADC 值 (Read ADC)

發送: 04 00 04 00

接收: 04 0A 23 00

計算: 0x0A23 = 2595

命令碼: 0x04

格式: 04 [Port] [Pin] 00

響應: 04 [High Byte] [Low Byte] 00

ADCValue = (High Byte << 8) | Low Byte

讀取指定 IO 的 ADC 轉換值(需先配置為模擬模式)。

示例: 讀取 PA04 的 ADC 值

3.5 中斷自動上報 (Interrupt Notify)

接收: 05 01 00 01 (PB00 變為高電平)

接收: 05 01 00 00 (PB00 變為低電平)

命令碼: 0x05

格式: 05 [Port] [Pin] [State]

[State]: 中斷發生后的當前電平 (00 或 01)

當 IO 配置為中斷模式 (0x03) 后,電平發生變化(上升沿或下降沿)時,設備會自動發送此幀。

示例: PB00 電平跳變

3.6 重啟設備 (System Reset)

復位微控制器。

發送: 06 00 00 00

接收: 06 01 00 00

格式: 06 00 00 00

響應: 06 01 00 00 (收到響應后設備將立即重啟)

命令碼: 0x06

示例: 重啟設備

4. 實現代碼

串口初始化,中斷處理

volatile uint8_t rx_buffer[UART_RX_BUFFER_SIZE];
volatile uint16_t rx_index = 0;
volatile uint8_t cmd_ready = 0;
/**
 * @brief Initialize the debug UART1
 * @note PA00 RXD AF1  PA01 TXD AF1
 * 
 */
void Debug_Uart_Init(void)
{
    SYSCTRL_AHBPeriphClk_Enable(SYSCTRL_AHB_PERIPH_GPIOA | SYSCTRL_AHB_PERIPH_GPIOB, ENABLE);
    SYSCTRL_APBPeriphClk_Enable1(SYSCTRL_APB1_PERIPH_UART1, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    GPIO_InitStructure.Pins = GPIO_PIN_0;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.Pins = GPIO_PIN_1;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
    PA01_AFx_UART1TXD();
    PA00_AFx_UART1RXD();
    UART_InitTypeDef UART_InitStructure = {0};
    UART_InitStructure.UART_BaudRate = 115200;
    UART_InitStructure.UART_Source = UART_Source_PCLK;
    UART_InitStructure.UART_UclkFreq = 48000000; // 48MHz
    UART_InitStructure.UART_StopBits = UART_StopBits_1;
    UART_InitStructure.UART_Parity = UART_Parity_No ;
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
    UART_Init(CW_UART1, &UART_InitStructure);
    // Enable UART RX Interrupt
    UART_ITConfig(CW_UART1, UART_IT_RC, ENABLE);
    NVIC_EnableIRQ(UART1_IRQn);
    // Enable ADC Clock
    SYSCTRL_APBPeriphClk_Enable1(SYSCTRL_APB1_PERIPH_ADC, ENABLE);
}
int fputc(int ch, FILE *f)
{
    UART_SendData_8bit(CW_UART1, (uint8_t)ch);
    while (UART_GetFlagStatus(CW_UART1, UART_FLAG_TXE) == RESET);
    return ch;
}
void UART1_RxCallback(uint8_t data)
{
    if (rx_index < UART_RX_BUFFER_SIZE)
    {
        rx_buffer[rx_index++] = data;
        if (rx_index >= UART_RX_BUFFER_SIZE)
        {
            cmd_ready = 1;
        }
    }
}
/**
 * @brief This funcation handles UART1
 */
void UART1_IRQHandler(void)
{
    /* USER CODE BEGIN */
    if(UART_GetITStatus(CW_UART1, UART_IT_RC) != RESET)
    {
        uint8_t data = UART_ReceiveData_8bit(CW_UART1);
        UART_ClearITPendingBit(CW_UART1, UART_IT_RC);
        UART1_RxCallback(data);
    }
    /* USER CODE END */
}

2.循環讀取命令

while (1)
{
    Process_UART_Command();
}
void Process_UART_Command(void)
{
    if (cmd_ready)
    {
        uint8_t cmd = rx_buffer[0];
        uint8_t port = rx_buffer[1];
        uint8_t pin = rx_buffer[2];
        uint8_t param = rx_buffer[3];
        switch (cmd)
        {
            case CMD_SET_MODE:
                Cmd_SetMode(port, pin, param);
                break;
            case CMD_READ_PIN:
                Cmd_Read(port, pin);
                break;
            case CMD_WRITE_PIN:
                Cmd_Write(port, pin, param);
                break;
            case CMD_READ_ADC:
                Cmd_Read_ADC(port, pin);
                break;
            case CMD_RESET:
                Cmd_Reset();
                break;
            default:
                // Unknown command
                break;
        }
        // Reset buffer
        rx_index = 0;
        cmd_ready = 0;
        memset((void*)rx_buffer, 0, UART_RX_BUFFER_SIZE);
    }
}

3.0x01 配置指定 IO 的工作模式函數

void Cmd_SetMode(uint8_t port_idx, uint8_t pin, uint8_t mode)
{
    // Validate Pin
    if (!Is_Pin_Valid(port_idx, pin)) return;
    GPIO_TypeDef* gpio_port = Get_GPIO_Port(port_idx);
    uint16_t gpio_pin = Get_GPIO_Pin(pin);
    if (gpio_port == NULL) return;
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    GPIO_InitStructure.Pins = gpio_pin;
    if (mode == 0x01) // Output
    {
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    }
    else if (mode == 0x02) // Analog
    {
        GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
    }
    else if (mode == 0x03) // Interrupt (Double Edge)
    {
        GPIO_InitStructure.Mode = GPIO_MODE_INPUT; // Standard Input
        GPIO_InitStructure.IT = GPIO_IT_RISING | GPIO_IT_FALLING;
        // Enable NVIC for the port
        if (port_idx == PORT_A)
        {
            NVIC_EnableIRQ(GPIOA_IRQn);
        }
        else if (port_idx == PORT_B)
        {
            NVIC_EnableIRQ(GPIOB_IRQn);
        }
    }
    else // Input (Default to 0x00)
    {
        GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    }
    GPIO_Init(gpio_port, &GPIO_InitStructure);
    // Return success: [CMD] [PORT] [PIN] [0x01]
    printf("%c%c%c%c", CMD_SET_MODE, port_idx, pin, 0x01);
}

4.0x02 讀取指定 IO 當前的電平狀態。

void Cmd_Read(uint8_t port_idx, uint8_t pin)
{
    // Validate Pin
    if (!Is_Pin_Valid(port_idx, pin)) return;
    GPIO_TypeDef* gpio_port = Get_GPIO_Port(port_idx);
    uint16_t gpio_pin = Get_GPIO_Pin(pin);
    if (gpio_port == NULL) return;
    uint8_t state = GPIO_ReadPin(gpio_port, gpio_pin);
    // Return format: [CMD] [PORT] [PIN] [STATE]
    printf("%c%c%c%c", CMD_READ_PIN, port_idx, pin, state);
}

5.0x03控制指定 IO 輸出高低電平(需先配置為輸出模式)。

void Cmd_Write(uint8_t port_idx, uint8_t pin, uint8_t value)
{
    // Validate Pin
    if (!Is_Pin_Valid(port_idx, pin)) return;
    GPIO_TypeDef* gpio_port = Get_GPIO_Port(port_idx);
    uint16_t gpio_pin = Get_GPIO_Pin(pin);
    if (gpio_port == NULL) return;
    GPIO_WritePin(gpio_port, gpio_pin, (value ? GPIO_Pin_SET : GPIO_Pin_RESET));
    // Return success: [CMD] [PORT] [PIN] [0x01]
    printf("%c%c%c%c", CMD_WRITE_PIN, port_idx, pin, 0x01);
}

6.0x04讀取指定 IO 的 ADC 轉換值(需先配置為模擬模式)。

uint32_t Get_ADC_Channel(uint8_t port_idx, uint8_t pin)
{
    // Mapping based on CW32L010 datasheet/header
    // PA00 -> ADC_IN0 ... PA07 -> ADC_IN7 (Note: PA07 is not available on all packages, check specific map)
    // Actually from cw32l010_adc.h comments:
    // PA00->CH0, PA01->CH1, PA02->CH2, PA03->CH3, PA04->CH4, PA05->CH5, PA06->CH6
    // PB00->CH7, PB01->CH8, PB02->CH9, PB03->CH10, PB04->CH11, PB05->CH12, PB06->CH13
    if (port_idx == PORT_A)
    {
        if (pin <= 6) return (uint32_t)pin; // CH0-CH6
    }
    else if (port_idx == PORT_B)
    {
        if (pin <= 6) return (uint32_t)(pin + 7); // CH7-CH13
    }
    return 0xFFFFFFFF; // Invalid
}
void Cmd_Read_ADC(uint8_t port_idx, uint8_t pin)
{
    // Validate Pin
    if (!Is_Pin_Valid(port_idx, pin)) return;
    uint32_t adc_ch = Get_ADC_Channel(port_idx, pin);
    if (adc_ch == 0xFFFFFFFF) return;
    ADC_InitTypeDef ADC_InitStructure = {0};
    ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div4;
    ADC_InitStructure.ADC_ConvertMode = ADC_ConvertMode_Once;
    ADC_InitStructure.ADC_SQREns = ADC_SqrEns0to0;
    ADC_InitStructure.ADC_IN0.ADC_InputChannel = adc_ch;
    ADC_InitStructure.ADC_IN0.ADC_SampTime = ADC_SampTime12Clk;
    ADC_Init(&ADC_InitStructure);
    ADC_Enable();
    ADC_SoftwareStartConvCmd(ENABLE);
    // Wait for conversion (simple polling with timeout)
    uint32_t timeout = 10000;
    while (timeout--)
    {
        if (ADC_GetITStatus(ADC_IT_EOC) != RESET)
        {
            ADC_ClearITPendingBit(ADC_IT_EOC);
            break;
        }
    }
    uint16_t result = ADC_GetConversionValue(0); // Get result from SQR0
    ADC_Disable();
    // Return: [CMD] [High Byte] [Low Byte] [0x00]
    printf("%c%c%c%c", CMD_READ_ADC, (uint8_t)(result >> 8), (uint8_t)(result & 0xFF), 0x00);
}

7.0x05當 IO 配置為中斷模式 (0x03) 后,電平發生變化(上升沿或下降沿)時,設備會自動發送此幀。

/**
 * @brief This funcation handles GPIOA
 */
void GPIOA_IRQHandler(void)
{
    /* USER CODE BEGIN */
    GPIO_ISR_Handler(PORT_A);
    /* USER CODE END */
}
/**
 * @brief This funcation handles GPIOB
 */
void GPIOB_IRQHandler(void)
{
    /* USER CODE BEGIN */
    GPIO_ISR_Handler(PORT_B);
    /* USER CODE END */
}
void GPIO_ISR_Handler(uint8_t port_idx)
{
    GPIO_TypeDef* gpio_port = Get_GPIO_Port(port_idx);
    if (gpio_port == NULL) return;
    uint16_t isr = gpio_port->ISR;
    for (uint8_t i = 0; i < 16; i++)
    {
        // Check validity first
        if (!Is_Pin_Valid(port_idx, i)) continue;
        uint16_t pin_mask = (1 ICR = ~pin_mask;
            // Read current state
            uint8_t state = (gpio_port->IDR & pin_mask) ? 1 : 0;
            // Send notification: [CMD_IT_NOTIFY] [PORT] [PIN] [STATE]
            printf("%c%c%c%c", CMD_IT_NOTIFY, port_idx, i, state);
        }
    }
}

8.0x06 復位微控制器。

void Cmd_Reset(void)
{
    // Send acknowledgement: [CMD_RESET] [0x01] [0x00] [0x00]
    printf("%c%c%c%c", CMD_RESET, 0x01, 0x00, 0x00);
    // Wait for UART transmission
    delay_ms(50);
    // Reset System
    NVIC_SystemReset();
}

5. 完整代碼

完成代碼請訪問倉庫:
https://gitee.com/aotengyang/open-source-code

固件使用 VScode EIDE 插件進行開發,如需使用keil進行編譯,需要將依賴的文件添加。

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • adc
    adc
    +關注

    關注

    100

    文章

    7755

    瀏覽量

    556615
  • GPIO
    +關注

    關注

    16

    文章

    1332

    瀏覽量

    56356
  • CW32
    +關注

    關注

    1

    文章

    323

    瀏覽量

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    CW32L010_ADC介紹

    CW32L010_ADC特性概述 分辨率與采樣率:CW32L010ADC具有12位分辨率,這意味著它能夠提供較高的精度。同時,其采樣率可達2M,這使得
    發表于 11-28 07:52

    CW32L010的串口輸出

    CW32L010款集成了豐富功能的低功耗微控制器,其串口輸出功能是通過其內部的通用異步收發器(UART)實現的。 、串口硬件資源 CW32L010提供了二路低功耗UART,這些U
    發表于 11-27 07:27

    CW32L010用FLASH模擬EEPROM

    CW32L010橫空出世,定時器和ADC變化很大,FLASH基本和以前型號樣,但有點改動,BUSY位從CR1寄存器改到ISR寄存器了。 把F003的程序改改就能用,太棒了,拿走不謝
    發表于 11-24 07:40

    CW32L010的內部框圖

    CW32L010系列產品是基于 eFlash 的單芯片低功耗微控制器,集成了主頻高達 48MHz 的 ARM? Cortex?-M0+ 內核、高速嵌入式存儲器(多至 64K 字節 FLASH 和多至 4K 字節 SRAM)以及系列全面的增強型外設和 I/O 口。
    發表于 11-21 06:40

    CW32L010用jlink能去除讀保護嗎?

    如題,板上的CW32L010有讀保護,JLINK能識別到內核,但無法擦除下載程序。 要怎么才能去除讀保護呢
    發表于 11-20 06:23

    CW32L010ADC采樣值波動導致電機調速不平滑怎么解決?

    CW32L010ADC采樣值波動導致電機調速不平滑
    發表于 11-18 06:30

    CW32L010高速風筒方案的特點

    CW32L010F8P6集成了多種外設接口,所有型號都提供全套的通信接口(二路 UART、路 SPI 和路 I2C)、12 位高速 ADC、四組通用和基本定時器、
    發表于 11-13 06:21

    請問CW32L010 能否使用SysTick中斷?

    CW32L010 能否使用SysTick中斷?
    發表于 11-12 07:25

    CW32L010系列的特點

    CW32L010系列MCU采用了獨特的工藝制程,使其待機電流降低至僅3uA,這在高溫環境下也表現得尤為出色,漏電僅為競品平均水平的四分之到八分之。此外,我們還全新設計了高級定時器,不僅兼容G4
    發表于 11-12 06:51

    基于CW32L010的高性能溫控器方案

    武漢芯源半導體的明星產品CW32L010系列MCU憑借其ARM Cortex-M0+內核、超低功耗特性以及豐富的外設接口,為溫控器設計提供了理想的解決方案。 本文將介紹無錫梓軒電子基于武漢芯源半導體低功耗CW32L010單片機開發的溫控器方案,功能全面,性價比突出。
    的頭像 發表于 07-02 09:47 ?1373次閱讀
    基于<b class='flag-5'>CW32L010</b>的高性能溫控器方案

    基于CW32L010的高性能溫控器方案

    功耗設計: CW32L010采用先進的工藝制程,待機電流僅0.3μA,即使在85℃高溫環境下,漏電流也僅為1.2μA,遠低于同類競品。這特性使得采用電池供電的溫控器能夠實現長達數年的工作壽命,大大減少了維護需求
    發表于 07-02 09:46

    基于CW32L010單片機的掃振體電動牙刷應用方案

    大幅擺動實現了高效的刷牙方式,這種設計能夠更高效地清潔牙齒和牙齦溝,為用戶帶來全新的潔牙體驗?。本文將介紹武漢芯源半導體CW32L010單片機在掃振體電動牙刷上的應用方案。 圖1:電動牙刷方案
    發表于 06-17 09:38

    CW32L010 ESC Driver 電機控制套件使用

    CW32L010ESC_Driver電機驅動板是武漢芯源科技推出的款低成本BLDC無刷直流電機開發板。在立創開源硬件平臺可以查看該項目的詳情。 https://oshwhub.com
    發表于 06-13 18:12

    武漢芯源半導體CW32L010在兩輪車儀表的應用介紹

    CW32L010憑借其優異的性能、豐富的外設資源和超低功耗特性,為兩輪車儀表盤應用提供了高性價比的解決方案。其寬電壓工作范圍和工業級溫度特性,特別適合車輛電子應用的嚴苛環境。對于想采用CW32L010進行兩輪車儀表盤開發的客戶,武漢芯源半導體可提供全面的技術支持,助力客戶
    的頭像 發表于 05-13 14:07 ?904次閱讀
    武漢芯源半導體<b class='flag-5'>CW32L010</b>在兩輪車儀表的應用介紹

    武漢芯源半導體CW32L010在兩輪車儀表的應用介紹

    通用和基本定時器、組低功耗定時器以及組高級控制 PWM 定時器。 CW32L010 可以在 -40℃到 85℃的溫度范圍內工作,供電電壓寬達 1.62V ~ 5.5V。支持 Sleep
    發表于 05-13 14:06