【MiniCH32V203EVB应用案例指南】

MiniCH32V203EVB应用案例指南

第一部分、前言

由于作者水平有限,文档和视频中难免有出错和讲得不好的地方,欢迎各位读者和观众善意地提出意见和建议,谢谢!本文档是MiniCH32V203评估板案例的指南,主要是一些相关硬件说明和代码讲解;如有疑问,可发邮件到以下邮箱:

1101495766@qq.com

购买方式:

  • 淘宝:https://item.taobao.com/item.htm?ft=t&id=768285052770

  • B站工房:https://mall.bilibili.com/neul-next/index.html?page=mall-up_itemDetail&noTitleBar=1&itemsId=1104871067&from=items_share&msource=items_share

资料下载:资料与评估板配套,购买后向客服索取;

第二部分、硬件概述

2.1 实物图:

在这里插入图片描述

从上图可以看出,CH32V203评估板提供了12V,5V,3.3V供电需求,同时板载两个Type-C 接口,同时扩充丰富的接口和功能模块,特别适合开发工程师验证与初学者的学习。

2.1 原理图:

在这里插入图片描述

第三部分、USB应用案例

3.1 按键编码器模拟鼠标:

该案例是使用一个五向按键模块和一个旋转编码器模块实现一个模拟鼠标的功能,其中按键模块五向按键实现的是鼠标的XY和左中右按键,而旋转编码器模块实现的是滚轮上下功能;

3.1.1硬件说明:

我们把用到的IO功能表列出来,用以后续软件作为参考;

IO名称复用/映射功能描述
PA0TIM2_CH1用作编码器接口输入A
PA1TIM2_CH2用作编码器接口输入B
PA2GPIO上拉输入检测UP按键
PA3GPIO上拉输入检测DWN按键
PA4GPIO上拉输入检测LFT按键
PA5GPIO上拉输入检测RHT按键
PA6GPIO上拉输入检测MID按键
PA7GPIO上拉输入检测SET按键
PA8GPIO上拉输入检测RST按键
3.1.2 程序设计:

程序主要分为三部分:一是一般外设驱动,二是USB HID驱动,三是应用代码;

3.1.2.1 外设驱动

按键驱动:Button_Init()主要是配置相关IO作为输入,Button_Handler是传入鼠标buffer把对应的数据解析一下;如上下左右按键就是模拟XY的,SET、RST和MID则是左右中按键;

void Button_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure = { 0 };

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4
            | GPIO_Pin_5 | GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Button_Handler(u8 *buf) {
    //Y
    if ((UP_ButtonSta() == Bit_RESET) && (DWN_ButtonSta() != Bit_RESET)) {
        buf[2] = -STEP;
    } else if ((UP_ButtonSta() != Bit_RESET)
            && (DWN_ButtonSta() == Bit_RESET)) {
        buf[2] = STEP;
    } else {
        buf[2] = 0;
    }
    //X
    if ((LFT_ButtonSta() == Bit_RESET) && (RHT_ButtonSta() != Bit_RESET)) {
        buf[1] = -STEP;
    } else if ((LFT_ButtonSta() != Bit_RESET)
            && (RHT_ButtonSta() == Bit_RESET)) {
        buf[1] = STEP;
    } else {
        buf[1] = 0;
    }
    //中键
    if (MID_ButtonSta() == Bit_RESET) {
        buf[0] |= 0x04;
    } else {
        buf[0] &= ~0x04;
    }
    //左键
    if (SET_ButtonSta() == Bit_RESET) {
        buf[0] |= 0x01;
    } else {
        buf[0] &= ~0x01;
    }
    //右键
    if (RST_ButtonSta() == Bit_RESET) {
        buf[0] |= 0x02;
    } else {
        buf[0] &= ~0x02;
    }
}

旋转编码器:EncoderInit()配置TIM2为编码器接口模式,map()是把编码器输出的数据限制在8bit以内,EncoderHandler是把编码器数据转出滚轮数据;

void EncoderInit(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_ICInitTypeDef TIM_ICInitStructure;
    //使能相应时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);   //使能AFIO复用功能模块时钟

    //GPIO初始化配置 TIM2_CH1(PA0)  TIM2_CH2(PA1)

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //定时器初始化配置

    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;                  //计数器自动重装载值

    TIM_TimeBaseStructure.TIM_Prescaler = 1;                    //预分频器值

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            //重复计数器值

    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //初始化结构体

    TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12,
    TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //使用编码器模式3

    //输入捕获配置

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 | TIM_Channel_2;

    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //输入捕获极性设置,可用于配置编码器正反相

    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;           //输入捕获预分频器设置

    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入捕获通道选择,编码器模式需选用此配置

    TIM_ICInitStructure.TIM_ICFilter = 10;                           //输入捕获滤波器设置

    TIM_ICInit(TIM2, &TIM_ICInitStructure);

//    TIM_ClearFlag(TIM2, TIM_FLAG_Update);        //清除TIM更新标志位
//
//    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);   //使能开启TIM中断

    //Reset counter

    TIM_SetCounter(TIM2, 0);

    TIM_Cmd(TIM2, ENABLE);
}
/*
在这个例子中,map 函数的参数解释如下:
x: 输入值
in_min 和 in_max: 输入范围的最小值和最大值
out_min 和 out_max: 输出范围的最小值和最大值
*/
s8 map(s16 x, s16 in_min, s16 in_max, s16 out_min, s16 out_max) {
    if(x>in_max)
    {
        return  10;
    }else if(x<in_min)
    {
        return  -10;
    }else{
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    }

}


s8 EncoderHandler(void)
{
    s8 encout;
    s16 enc= TIM_GetCounter(TIM2);

    TIM_SetCounter(TIM2,0);
    encout=map(enc,-100,100,-127,127);
    printf("enc = %d\r\n", enc);
    printf("enc1 = %d\r\n", encout);
    return encout;
}
3.1.2.2 USB驱动

USB 传输事务的处理:USBHD_IRQHandler是传输事务的处理,这里我们只看标准请求里面的获取描述符请求,其中USB_DESCR_TYP_DEVICE是获取设备描述符;

USB_DESCR_TYP_CONFIG是获取配置描述符集合,该集合有配置描述符、接口描述符、HID描述符、端点描述符;

USB_DESCR_TYP_HID是获取HID描述符;

USB_DESCR_TYP_REPORT是获取报告描述符;

USB_DESCR_TYP_STRING是获取字符串描述符,字符串描述符又分语言ID描述符、厂商字符串描述符、产品字符串描述符、序列号字符串描述符;

                       case USB_GET_DESCRIPTOR:
                            switch( (uint8_t)( USBFS_SetupReqValue >> 8 ) )
                            {
                                /* get usb device descriptor */
                                case USB_DESCR_TYP_DEVICE:
                                    pUSBFS_Descr = MyDevDescr;
                                    len = DEF_USBD_DEVICE_DESC_LEN;
                                    break;

                                /* get usb configuration descriptor */
                                case USB_DESCR_TYP_CONFIG:
                                    pUSBFS_Descr = MyCfgDescr;
                                    len = DEF_USBD_CONFIG_DESC_LEN;
                                    break;

                                /* get usb hid descriptor */
                                case USB_DESCR_TYP_HID:
                                    if( USBFS_SetupReqIndex == 0x00 )
                                    {
                                        pUSBFS_Descr = &MyCfgDescr[ 18 ];
                                        len = 9;
                                    }

                                    else
                                    {
                                        errflag = 0xFF;
                                    }
                                    break;

                                /* get usb report descriptor */
                                case USB_DESCR_TYP_REPORT:
                                    if( USBFS_SetupReqIndex == 0x00 )
                                    {
                                        pUSBFS_Descr = MouseRepDesc;
                                        len = DEF_USBD_REPORT_DESC_LEN_MS;
                                    }
                                    else
                                    {
                                        errflag = 0xFF;
                                    }
                                    break;

                                /* get usb string descriptor */
                                case USB_DESCR_TYP_STRING:
                                    switch( (uint8_t)( USBFS_SetupReqValue & 0xFF ) )
                                    {
                                        /* Descriptor 0, Language descriptor */
                                        case DEF_STRING_DESC_LANG:
                                            pUSBFS_Descr = MyLangDescr;
                                            len = DEF_USBD_LANG_DESC_LEN;
                                            break;

                                        /* Descriptor 1, Manufacturers String descriptor */
                                        case DEF_STRING_DESC_MANU:
                                            pUSBFS_Descr = MyManuInfo;
                                            len = DEF_USBD_MANU_DESC_LEN;
                                            break;

                                        /* Descriptor 2, Product String descriptor */
                                        case DEF_STRING_DESC_PROD:
                                            pUSBFS_Descr = MyProdInfo;
                                            len = DEF_USBD_PROD_DESC_LEN;
                                            break;

                                        /* Descriptor 3, Serial-number String descriptor */
                                        case DEF_STRING_DESC_SERN:
                                            Get_SerialNum();
                                            pUSBFS_Descr = USBD_StringSerial;
                                            len = USBD_StringSerial[0];
                                            break;

                                        default:
                                            errflag = 0xFF;
                                            break;
                                    }
                                    break;

                                default :
                                    errflag = 0xFF;
                                    break;
                            }

                            /* Copy Descriptors to Endp0 DMA buffer */
                            if( USBFS_SetupReqLen > len )
                            {
                                USBFS_SetupReqLen = len;
                            }
                            len = ( USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ) ? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen;
                            memcpy( USBFS_EP0_Buf, pUSBFS_Descr, len );
                            pUSBFS_Descr += len;
                            break;
3.1.2.3 应用代码

这里的应用代码,主要是使用了MultiTimer组件整合了外设驱动和USB HID数据上报


#include "PollSystem.h"
#include "Button.h"
#include "Encoder.h"
#include "ch32v20x_usbfs_device.h"
vu32 uwTick;

MultiTimer timer1;
MultiTimer timer2;


u8 Mouse_Report[4] = { 0 };


void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

uint64_t PlatformTicksGetFunc(void) {
    return uwTick;
}

u8 buttonSemaphore = 0;

void ButtonTimer1Callback(MultiTimer* timer, void *userData) {
    static u8 lastbut=0;
    Button_Handler(Mouse_Report);
    Mouse_Report[3]=EncoderHandler();
    if((Mouse_Report[1]!=0)||(Mouse_Report[2]!=0)||(Mouse_Report[3]!=0)||(Mouse_Report[0]!=lastbut))
    {
        buttonSemaphore = 1;
        lastbut=Mouse_Report[0];
    }

    MultiTimerStart(timer, 5, ButtonTimer1Callback, userData);
}



void JoystickTimer3Callback(MultiTimer* timer, void *userData) {

    if(buttonSemaphore)
    {
        buttonSemaphore=0;
        USBFS_Endp_DataUp( DEF_UEP1, Mouse_Report, sizeof( Mouse_Report ), DEF_UEP_CPY_LOAD );
    }

    MultiTimerStart(timer, 5, JoystickTimer3Callback, userData);
}




void SYSTICK_Init_Config(u64 ticks)
{
    SysTick->SR = 0;
    SysTick->CNT = 0;
    SysTick->CMP = ticks;
    SysTick->CTLR =0xF;

    NVIC_SetPriority(SysTicK_IRQn, 15);
    NVIC_EnableIRQ(SysTicK_IRQn);
}



void PollSystemInit(void) {
    SYSTICK_Init_Config(SystemCoreClock/1000-1);
    MultiTimerInstall(PlatformTicksGetFunc);
    MultiTimerStart(&timer1, 5, ButtonTimer1Callback, NULL);
    MultiTimerStart(&timer2, 5, JoystickTimer3Callback,NULL);
}

void SysTick_Handler(void)
{
    SysTick->SR = 0;
    uwTick++;

}

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值