CH573(一) 基础外设
教程来自链接
不得不吐槽一下, 沁恒的库真的很浅, 和 STM 的 HAL 库比,通过两个跳转就能看见它的寄存器操作,麻了. 好吧好处就是能让我知道原理, 坏处就是调用草率,不容易懂.
(一) 点灯
#include "CH57x_common.h"
int main(){
SetSysClock(CLK_SOURCE_PLL_60MHz);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeOut_PP_5mA);
while(1){
GPIOA_ResetBits(GPIO_Pin_8); //LED点亮
mDelaymS(1000); //持续0.5s
GPIOA_SetBits(GPIO_Pin_8); //LED熄灭
mDelaymS(1000); //持续0.5s
}
}
(二) 按键输入
#include "CH57x_common.h"
#define KEY1_PIN GPIO_Pin_22
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeIN_PU);//KEY1_PIN上拉输入
while(1)
{
if(GPIOA_ReadPortPin(KEY1_PIN)==0){
DelayMs(10);
if(GPIOA_ReadPortPin(KEY1_PIN)==0){
//do nothing
}
}
DelayMs(50);
}
}
(三) 中断
#include "CH57x_common.h"
#define KEY1_PIN GPIO_Pin_4
int main() {
SetSysClock(CLK_SOURCE_PLL_60MHz);
GPIOB_ModeCfg(KEY1_PIN, GPIO_ModeIN_PU); //KEY3_PIN设置为上拉输入
GPIOB_ITModeCfg(KEY1_PIN, GPIO_ITMode_FallEdge);//KEY3_PIN下降沿触发中断
PFIC_EnableIRQ(GPIO_B_IRQn); //使能GPIOB端口中断
while (1) {
DelayMs(50);
}
}
//设置外部中断相关函数属性,指定声明相关特征
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
/*
* 函数名:GPIOB_IRQHandler
* 参数:无
* 返回值:无
* 功能说明:GPIOB端口的中断处理函数
*/
void GPIOB_IRQHandler(void) {
//判断GPIOB端口的中断标志
if (GPIOB_ReadITFlagBit(KEY1_PIN)) {
//do nothing
}
//清空中断标志位
GPIOB_ClearITFlagBit(KEY1_PIN);
}
(四) 定时器
#include "CH57x_common.h"
int main() {
SetSysClock(CLK_SOURCE_PLL_60MHz);
uint32_t time = 500;//定时500ms
TMR0_TimerInit(FREQ_SYS / (1000 / time));//定时器0初始化:
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断
PFIC_EnableIRQ(TMR0_IRQn);
while (1) {
DelayMs(50);
}
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
/*********************************************************************************************************
* 函 数 名: TMR0_IRQHandler()
* 功能说明: 定时器TMR0中断函数(LED翻转电平)
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************/
void TMR0_IRQHandler(void) {
if (TMR0_GetITFlag(TMR0_3_IT_CYC_END)) {
TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志
//do nothing
}
}
(五) PWM
#include "CH57x_common.h"
int main() {
SetSysClock(CLK_SOURCE_PLL_60MHz);
//基于定时器的引脚PWM初始化:PA9\PA10\PA11\PB22
GPIOB_ResetBits(GPIO_Pin_22); // 配置PWM口 PB22
GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeOut_PP_5mA);
TMR3_PWMInit(High_Level, PWM_Times_1);
TMR3_PWMCycleCfg(6000); // 周期 100us
//PWM引脚初始化:PB14\PB7\PB4\PB23\PA13\PA12\PB6\PB0:
GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeOut_PP_5mA); // PA12 - PWM4
PWMX_CLKCfg(4); // cycle = 4/Fsys
PWMX_CycleCfg(PWMX_Cycle_64); // 周期 = 64*cycle
PWMX_ACTOUT(CH_PWM4, 64 / 4, Low_Level, ENABLE); // 25% 占空比
while (1) {
//呼吸灯1
for (uint16_t i = 0; i < 6000; i += 20) {
TMR3_Disable();
TMR3_PWMActDataWidth(i); //修改占空比必须暂时关闭定时器
TMR3_Enable();
DelayMs(2);
}
for (uint16_t i = 6000; i > 0; i -= 20) {
TMR3_Disable();
TMR3_PWMActDataWidth(i); // 修改占空比必须暂时关闭定时器
TMR3_Enable();
DelayMs(2);
}
//呼吸灯2
for (uint16_t i = 1; i < 64; i++) {
PWMX_ACTOUT(CH_PWM4, 64 / i, Low_Level, ENABLE);
DelayMs(5);
}
for (uint16_t i = 64; i > 1; i--) {
PWMX_ACTOUT(CH_PWM4, 64 / i, Low_Level, ENABLE);
DelayMs(5);
}
}
}
(六) 串口
#include "CH57x_common.h"
uint8_t Tx0Buff[] = "Hello by UART0 --- FUNIOT.XYZ!\r\n";
uint8_t Rx0Buff[100];
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置串口0:先配置IO口模式,再配置串口 */
GPIOB_SetBits(GPIO_Pin_7);
GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU); // RXD0-配置上拉输入
GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA); // TXD0-配置推挽输出,注意先让IO口输出高电
UART0_DefInit(); //初始化默认配置,波特率115200
//配置串口0中断接收模式
UART0_ByteTrigCfg(UART_7BYTE_TRIG);
UART0_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
PFIC_EnableIRQ(UART0_IRQn);
while(1)
{
UART0_SendString(Tx0Buff, sizeof(Tx0Buff));
DelayMs(2000);
}
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART0_IRQHandler(void)
{
volatile uint8_t i;
if(UART_II_RECV_TOUT) // 接收超时,暂时一帧数据接收完成
{
i = UART0_RecvString(Rx0Buff); //接收数据并记录长度
UART0_SendString(Rx0Buff, i); //将接收的数据串口发送
//自行数据解析
}
}
(七) ADC
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.c
* Author : WCH
* Version : V1.0
* Date : 2021/03/09
* Description : adc采样示例,包括温度检测、单通道检测、差分通道检测、TouchKey检测、中断方式采样。
*********************************************************************************
* 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.
*******************************************************************************/
#include "CH57x_common.h"
uint16_t adcBuff[40];
volatile uint8_t adclen;
volatile uint8_t DMA_end = 0;
/*********************************************************************
* @fn DebugInit
*
* @brief 调试初始化
*
* @return none
*/
void DebugInit(void)
{
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
}
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main()
{
uint8_t i;
signed short RoughCalib_Value = 0; // ADC粗调偏差值
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置串口调试 */
DebugInit();
PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
/* 温度采样并输出 */
PRINT("\n1.Temperature sampling...\n");
ADC_InterTSSampInit();
for(i = 0; i < 20; i++)
{
adcBuff[i] = ADC_ExcutSingleConver(); // 连续采样20次
}
for(i = 0; i < 20; i++)
{
PRINT("%d \n", adc_to_temperature_celsius(adcBuff[i]));
}
/* 单通道采样:选择adc通道0做采样,对应 PA4引脚, 带数据校准功能 */
PRINT("\n2.Single channel sampling...\n");
GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_Floating);
ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);
RoughCalib_Value = ADC_DataCalib_Rough(); // 用于计算ADC内部偏差,记录到全局变量 RoughCalib_Value中
PRINT("RoughCalib_Value =%d \n", RoughCalib_Value);
ADC_ChannelCfg(0);
for(i = 0; i < 20; i++)
{
adcBuff[i] = ADC_ExcutSingleConver() + RoughCalib_Value; // 连续采样20次
}
for(i = 0; i < 20; i++)
{
PRINT("%d \n", adcBuff[i]); // 注意:由于ADC内部偏差的存在,当采样电压在所选增益范围极限附近的时候,可能会出现数据溢出的现象
}
/* DMA单通道采样:选择adc通道0做采样,对应 PA4引脚 */
PRINT("\n3.Single channel DMA sampling...\n");
GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_Floating);
ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);
ADC_ChannelCfg(0);
ADC_AutoConverCycle(192); // 采样周期为 (256-192)*16个系统时钟
ADC_DMACfg(ENABLE, (uint16_t)(uint32_t)&adcBuff[0], (uint16_t)(uint32_t)&adcBuff[40], ADC_Mode_Single);
PFIC_EnableIRQ(ADC_IRQn);
ADC_StartDMA();
while(!DMA_end);
DMA_end = 0;
ADC_DMACfg(DISABLE, 0, 0, 0);
for(i = 0; i < 40; i++)
{
PRINT("%d \n", adcBuff[i]);
}
/* 差分通道采样:选择adc通道0做采样,对应 PA4(AIN0)、PA12(AIN2) */
PRINT("\n4.Diff channel sampling...\n");
GPIOA_ModeCfg(GPIO_Pin_4 | GPIO_Pin_12, GPIO_ModeIN_Floating);
ADC_ExtDiffChSampInit(SampleFreq_3_2, ADC_PGA_0);
ADC_ChannelCfg(0);
for(i = 0; i < 20; i++)
{
adcBuff[i] = ADC_ExcutSingleConver(); // 连续采样20次
}
for(i = 0; i < 20; i++)
{
PRINT("%d \n", adcBuff[i]);
}
/* TouchKey采样:选择adc通道 2 做采样,对应 PA12 */
PRINT("\n5.TouchKey sampling...\n");
GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeIN_Floating);
TouchKey_ChSampInit();
ADC_ChannelCfg(2);
for(i = 0; i < 20; i++)
{
adcBuff[i] = TouchKey_ExcutSingleConver(0x10, 0); // 连续采样20次
}
for(i = 0; i < 20; i++)
{
PRINT("%d \n", adcBuff[i]);
}
/* 单通道采样:中断方式,选择adc通道1做采样,对应 PA5引脚, 不带数据校准功能 */
PRINT("\n6.Single channel sampling in interrupt mode...\n");
GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_Floating);
ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);
ADC_ChannelCfg(1);
adclen = 0;
ADC_ClearITFlag();
PFIC_EnableIRQ(ADC_IRQn);
ADC_StartUp();
while(adclen < 20);
PFIC_DisableIRQ(ADC_IRQn);
for(i = 0; i < 20; i++)
{
PRINT("%d \n", adcBuff[i]);
}
while(1);
}
/*********************************************************************
* @fn ADC_IRQHandler
*
* @brief ADC中断函数
*
* @return none
*/
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void ADC_IRQHandler(void) //adc中断服务程序
{
if(ADC_GetDMAStatus())
{
ADC_StopDMA();
R16_ADC_DMA_BEG = ((uint32_t)adcBuff) & 0xffff;
ADC_ClearDMAFlag();
DMA_end = 1;
}
if(ADC_GetITStatus())
{
ADC_ClearITFlag();
if(adclen < 20)
{
adcBuff[adclen] = ADC_ReadConverValue();
ADC_StartUp(); // 作用清除中断标志并开启新一轮采样
}
adclen++;
}
}
(八) SPI
#include "CH57x_common.h"
__attribute__((aligned(4))) uint8_t spiBuff[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6};
__attribute__((aligned(4))) uint8_t spiBuffrev[16];
void DebugInit(void)
{
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
}
int main()
{
uint8_t i;
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置串口调试 */
DebugInit();
PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
#if 1
/* 主机模式 */
PRINT("1.spi0 mul master mode send data ...\n");
DelayMs(100);
GPIOA_SetBits(GPIO_Pin_12);
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
SPI0_MasterDefInit();
// 单字节发送
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterSendByte(0x55);
GPIOA_SetBits(GPIO_Pin_12);
DelayMs(1);
GPIOA_ResetBits(GPIO_Pin_12);
i = SPI0_MasterRecvByte();
GPIOA_SetBits(GPIO_Pin_12);
DelayMs(2);
// FIFO 连续发送
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterTrans(spiBuff, 9);
GPIOA_SetBits(GPIO_Pin_12);
DelayMs(1);
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterRecv(spiBuffrev, 12);
GPIOA_SetBits(GPIO_Pin_12);
DelayMs(1);
// DMA 连续发送
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterDMATrans(spiBuff, 12);
GPIOA_SetBits(GPIO_Pin_12);
DelayMs(1);
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterDMARecv(spiBuffrev, 12);
GPIOA_SetBits(GPIO_Pin_12);
PRINT("END ...\n");
while(1);
#endif
#if 0
/* 设备模式 */
PRINT("1.spi0 mul slave mode \n");
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_ModeIN_PU);
SPI0_SlaveInit();
i = SPI0_SlaveRecvByte();
SPI0_SlaveSendByte(~i);
SPI0_SlaveRecv(spiBuffrev, 9);
SPI0_SlaveTrans(spiBuffrev, 12);
SPI0_SlaveDMARecv(spiBuffrev, 12);
SPI0_SlaveDMATrans(spiBuffrev, 12);
while(1);
#endif
while(1);
}
License:
CC BY 4.0