친헝 CH32V307VCT6 최소 시스템 보드로, 모든 IO 핀을 브레이크아웃했으며, Type-C 하나는 USB2.0 Full-Speed OTG에 연결되고, 플래시 칩 W25Q64(용량 64 Mbit)는 SPI2에 연결되어 있습니다. 보드에는 TL432 전압 레퍼런스 1.25 V(실측 약 1.246 V)가 있어 점퍼로 PC3의 AD13에 연결 가능하며, 3.29 V 레퍼런스는 0 Ω 저항으로 ADC 기준 전압 VREF에 연결할 수 있습니다.
- MSP430F149 최소 시스템 보드를 그려 오픈소스로 공개했습니다: https://blog.zeruns.com/archives/713.html
- STM32F030C8T6 최소 시스템 보드와 물결 LED(회로도 및 PCB): https://blog.zeruns.com/archives/715.html
전자/마이크로컨트롤러 기술 모임 채팅방: 2169025065
CH32V307VCT6 소개
CH32V 시리즈는 칭커 32비트 RISC-V 기반의 산업용 범용 마이크로컨트롤러입니다. 전 제품에 하드웨어 스택 영역과 빠른 인터럽트 진입 설계를 적용해 표준 대비 인터럽트 응답 속도를 크게 향상시켰습니다. CH32V303_305_307 시리즈는 V4F 코어를 탑재해 단정도 부동소수점 명령어 세트를 지원하며, 더 높은 연산 성능을 제공합니다. 제품 기능으로는 144 MHz 메인 클럭 제로 웨이트 실행을 지원하며, 애플리케이션 방향에 따라 8组 USART/UART 시리얼 포트, 4组 모터 타이머, 내장 PHY 트랜시버를 갖춘 USB2.0 고속 인터페이스(480 Mbps), 기가비트 이더넷 MAC 등 특화된 리소스 구조를 제공합니다.
친헝 공식 제품 소개: https://url.zeruns.com/Hcd8p
샘플 무료 신청(배송료 착불): https://url.zeruns.com/x67TF
칩 데이터시트 다운로드: https://url.zeruns.com/hDzqw 압축코드: cn7c
실물 사진

회로도
도면의 Type-C 포트에 약간의 문제가 있습니다. CC1과 CC2는 5.1 kΩ 저항으로 각각 풀다운해야 하는데, 저는 병렬로 풀다운해 E-mark 케이블 사용 시 정상 전원 공급이 안 됩니다. 리창 오픈소스 프로젝트에서는 수정했습니다.
PCB
Top Layer:
TL432의 1.25 V(실측 약 1.246 V) 전압 레퍼런스는 H8 점퍼로 GPIO PC3의 ADC13에 연결할 수 있습니다.
SW3는 BOOT0 및 BOOT1 부트스트랩 핀을 제어해 부트 모드를 설정합니다(칩 매뉴얼 2.5.2 온칩 메모리 및 부트스트랩 모드 참조). 둘 다 로우(Off)로 설정하면 됩니다.
H9 핀헤더는 WCH-Link로 코드 다운로드용입니다.
H5 핀헤더는 VBAT 핀 전원 선택용입니다. 배터리 미장착 시 점퍼로 3.3 V에 연결하고, 배터리 장착 시 BAT에 연결합니다.
Bottom Layer:
외부 VDDA 전원과 VREF가 불필요하면 바닥면 R11과 R7에 0 Ω 저항을 장착한 후, VREF+는 R8과 R9로 LDO 출력 3.3 V 또는 TL432 출력 3.29 V 레퍼런스 중 선택해 연결하면 되며, 보통 R9에 연결하고 다른 쪽은 비워 둡니다.
부품 구매 링크
- 0805 저항 샘플북: https://u.jd.com/DzK9k0O
- 0805 커패시터 샘플북: https://s.click.taobao.com/cTZzzDu
- CH32V307VCT6: https://s.click.taobao.com/5SjzzDu
- W25Q64JV: https://s.click.taobao.com/YAv6NEu
- TL432: https://s.click.taobao.com/t3AzzDu
- WCH-Link: https://s.click.taobao.com/m6KyzDu
- 핀헤더: https://u.jd.com/DbKUBDu
부품 구매는 리창(立创) 몰 추천, 할인 가입 링크: https://activity.szlcsc.com/invite/D03E5B9CEAAE70A4.html
보드에 사용된 모든 부품은 리창 몰에서 구매 가능하며, 오픈소스 링크의 BOM에서 ‘리창 몰로 바로 주문’을 클릭하면 필요 부품을 한 번에 장바구니에 담을 수 있습니다.
예제 코드
전체 프로젝트 다운로드: https://url.zeruns.com/2q4tX 압축코드: 9527
리창 오픈소스 플랫폼 링크: https://url.zeruns.com/Avda8
예제는 Harmony LiteOS-M 시스템을 사용하며, 3개의 태스크를 생성합니다: LED2는 500 ms마다 깜빡임, LED3는 1초마다, LED4는 2초마다 깜빡입니다.(위 GIF는 1.5배속)
프로젝트는 MounRiver Studio로 열어야 합니다.
main.c 코드:
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "debug.h"
#include "los_tick.h"
#include "los_task.h"
#include "los_config.h"
#include "los_interrupt.h"
#include "los_debug.h"
#include "los_compiler.h"
/* Global define */
``````c
/* 전역 변수 */
__attribute__((aligned (8))) UINT8 g_memStart[LOSCFG_SYS_HEAP_SIZE];
UINT32 g_VlaueSp=0;
u8 i = 0,j=0,k=0;
/*********************************************************************
* @fn taskSampleEntry3
*
* @brief taskSampleEntry3 프로그램.
*
* @return none
*/
VOID taskSampleEntry3(VOID)
{
while(1) {
LOS_TaskDelay(2000);
printf("taskSampleEntry3 running,task3 SP:%08x\n",__get_SP());
GPIO_WriteBit(GPIOD, GPIO_Pin_13, (k == 0) ? (k = Bit_SET) : (k = Bit_RESET));
}
}
/*********************************************************************
* @fn taskSampleEntry2
*
* @brief taskSampleEntry2 프로그램.
*
* @return none
*/
VOID taskSampleEntry2(VOID)
{
while(1) {
LOS_TaskDelay(1000);
printf("taskSampleEntry2 running,task2 SP:%08x\n",__get_SP());
GPIO_WriteBit(GPIOD, GPIO_Pin_12, (j == 0) ? (j = Bit_SET) : (j = Bit_RESET));
}
}
/*********************************************************************
* @fn taskSampleEntry1
*
* @brief taskSampleEntry1 프로그램.
*
* @return none
*/
VOID taskSampleEntry1(VOID)
{
while(1) {
LOS_TaskDelay(500);
printf("taskSampleEntry1 running,task1 SP:%08x\n",__get_SP());
GPIO_WriteBit(GPIOD, GPIO_Pin_11, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));
}
}
// https://blog.zeruns.com
/*********************************************************************
* @fn EXTI0_INT_INIT
*
* @brief EXTI0 수집 초기화.
*
* @return none
*/
void EXTI0_INT_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
EXTI_InitTypeDef EXTI_InitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure={0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOA ----> EXTI_Line0 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_INIT(void) {
GPIO_InitTypeDef GPIO_InitStructure = { 0 };
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/*********************************************************************
* @fn taskSample
*
* @brief taskSample 프로그램.
*
* @return none
*/
UINT32 taskSample(VOID) {
UINT32 uwRet;
UINT32 taskID1, taskID2, taskID3;
TSK_INIT_PARAM_S stTask = { 0 };
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC) taskSampleEntry1;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry1";
stTask.usTaskPrio = 6;/* 높은 우선순위 */
uwRet = LOS_TaskCreate(&taskID1, &stTask);
if (uwRet != LOS_OK) {
printf("create task1 failed\n");
}
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC) taskSampleEntry2;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry2";
stTask.usTaskPrio = 7;/* 낮은 우선순위 */
uwRet = LOS_TaskCreate(&taskID2, &stTask);
if (uwRet != LOS_OK) {
printf("create task2 failed\n");
}
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC) taskSampleEntry3;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry3";
stTask.usTaskPrio = 7;/* 낮은 우선순위 */
uwRet = LOS_TaskCreate(&taskID3, &stTask);
if (uwRet != LOS_OK) {
printf("create task3 failed\n");
}
// https://blog.vpszj.cn
EXTI0_INT_INIT();
return LOS_OK;
}
/*********************************************************************
* @fn main
*
* @brief 메인 프로그램.
*
* @return none
*/
LITE_OS_SEC_TEXT_INIT int main(void)
{
unsigned int ret;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
SystemCoreClockUpdate();
Delay_Init();
GPIO_INIT();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
ret = LOS_KernelInit();
taskSample();
if (ret == LOS_OK)
{
LOS_Start();
}
GPIO_WriteBit(GPIOC, GPIO_Pin_1,RESET);
while (1) {
__asm volatile("nop");
}
}
/*********************************************************************
* @fn EXTI0_IRQHandler
*
* @brief 이 함수는 EXTI0 핸들러를 처리합니다.
*
* @return none
*/
void EXTI0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void EXTI0_IRQHandler(void)
{
/* 인터럽트 스택은 원래 main이 설정한 값을 사용하며, 인터럽트 스택과 스레드 스택을 분리하여 스레드가 인터럽트로 진입할 때
* 인터럽트 함수가 중첩 깊이가 크더라도 스레드 스택이 가득 차 오버플로우 되지 않도록 합니다. 그러나 현재 방식으로는
* 스레드가 인터럽트로 진입할 때 컴파일러가 저장하는 16개 caller 레지스터는 여전히 스레드 스택에 압축됩니다.
* caller 레지스터를 인터럽트 스택에 압축하려면 인터럽트 함수의 입구와 출구는 어셈블리를 사용하고,
* 중간에 사용자 인터럽트 처리 함수를 호출하면 됩니다. los_exc.S의 ipq_entry 예제를 참조하세요.
* */
GET_INT_SP();
HalIntEnter();
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
g_VlaueSp= __get_SP();
printf("Run at EXTI:");
printf("interruption sp:%08x\r\n",g_VlaueSp);
HalDisplayTaskInfo();
EXTI_ClearITPendingBit(EXTI_Line0); /* 플래그 지우기 */
}
HalIntExit();
FREE_INT_SP();
}
추천하는 다른 오픈소스 프로젝트
- SY8205 동기식 벅 조절 가능 DCDC 전원 모듈(원리도 및 PCB): https://blog.zeruns.com/archives/717.html
- 2011년 전국 전자대회 문제 - 스위칭 전원 모듈 병렬 공급 시스템: https://blog.zeruns.com/archives/718.html
- 2007년 전자대회 전원 문제: 30~36V 조절 가능 승압 DCDC 모듈(UC3843): https://oshwhub.com/zeruns/36v-sheng-ya-dcdc-mo-kuai-uc3842
- STC12C5A60S2 최소 시스템 보드/51 마이크로컨트롤러 온도 표시 및 온도 제어 팬: https://blog.zeruns.com/archives/721.html
- U8g2 그래픽 라이브러리를 이식한 STM32F407 표준 라이브러리 프로젝트 템플릿: https://blog.zeruns.com/archives/722.html
추천 읽기
- 높은 가성비와 저렴한 VPS/클라우드 서버 추천: https://blog.vpszj.cn/archives/41.html
- 개인 블로그 구축 방법: https://blog.zeruns.com/archives/218.html
- 마인크래프트 서버 구축 튜토리얼: https://blog.zeruns.com/tag/mc/
- STM32로 SHT3x 시리즈 온습도 센서 읽기: https://blog.zeruns.com/archives/700.html
- VSCode로 Keil 대체하여 STM32 및 51 마이크로컨트롤러 개발하기: https://blog.zeruns.com/archives/690.html
- 우윈 미국 고방 독서 성능 평가, 8코어 16G 50M 200G 방어: https://blog.vpszj.cn/archives/1603.html
- 테위윈 후베이 십옌 고방 VPS 성능 리뷰, 4코어 8G 10M 100G 방어: https://blog.vpszj.cn/archives/1523.html






