CH571F蓝牙orUSB摇杆鼠标

演示视频:

短视频刷个爽

程序基本上是基于官方的例程上改的,用到的例程有:蓝牙的HID_Mouse,USB的CompoundDev,还有ADC,按键中断。

主要原理

就是ADC采集采集摇杆电压,通过蓝牙HID或者USB的HID发送给电脑或者手机,实现鼠标功能。

软硬件开源链接

opencaneve: 开源STM32HAL ESP8266 ESP32 python Android Windows把我学习到的以及找到的可以用的代码分享出来python记录打卡信息 ESP32蓝牙鼠标 开源windows串口助手 - Gitee.com

简单讲一下程序逻辑

首先是初始化

int main(void)
{

#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
    PWR_DCDCCfg(ENABLE);
#endif
    SetSysClock(CLK_SOURCE_PLL_60MHz);
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
    GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
    GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
#endif
#ifdef DEBUG
    GPIOA_SetBits(bTXD1);
    GPIOA_ModeCfg(bTXD1, GPIO_ModeOut_PP_5mA);
    UART1_DefInit();
#endif

    pEP0_RAM_Addr = EP0_Databuf;
    pEP1_RAM_Addr = EP1_Databuf;
    pEP2_RAM_Addr = EP2_Databuf;
    pEP3_RAM_Addr = EP3_Databuf;
    USB_DeviceInit();
    PFIC_EnableIRQ(USB_IRQn);

    PRINT("%s\n", VER_LIB);
    CH57X_BLEInit();
    HAL_Init();
    GAPRole_PeripheralInit();
    HidDev_Init();
    HidEmu_Init();

    GPIOB_SetBits(GPIO_Pin_4);
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeOut_PP_5mA);
    TMR0_TimerInit(FREQ_SYS/100);         // 设置定时时间 100ms10
	TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断
	PFIC_EnableIRQ(TMR0_IRQn);

    PRINT("\n2.Single channel sampling...\n");
    GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_Floating);
    GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_Floating);
    ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_1_2);
//    RoughCalib_Value = ADC_DataCalib_Rough(); // 用于计算ADC内部偏差,记录到全局变量 RoughCalib_Value中
//    PRINT("RoughCalib_Value =%d \n", RoughCalib_Value);
	ADC_ChannelCfg(0);
	start_lr_adc = ADC_ExcutSingleConver(); //
    ADC_ChannelCfg(1);
	start_ud_adc = ADC_ExcutSingleConver(); //
	PRINT("%d %d \n", adcBuff[0],adcBuff[1]); // 注意:由于ADC内部偏差的存在,当采样电压在所选增益范围极限附近的时候,可能会出现数据溢出的现象

	GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeIN_PU);
	GPIOB_ITModeCfg(GPIO_Pin_7, GPIO_ITMode_FallEdge); // 下降沿唤醒
	GPIOB_ModeCfg(GPIO_Pin_13, GPIO_ModeIN_PU);
	GPIOB_ITModeCfg(GPIO_Pin_13, GPIO_ITMode_FallEdge); // 下降沿唤醒
	GPIOB_ModeCfg(GPIO_Pin_12, GPIO_ModeIN_PU);
	GPIOB_ITModeCfg(GPIO_Pin_12, GPIO_ITMode_FallEdge); // 下降沿唤醒
	PFIC_EnableIRQ(GPIO_B_IRQn);


    Main_Circulation();


}

 这部分基本上直接从例程中copy过来融合在一起

然后是定时器中断,

虽然好像蓝牙也有个类似于任务排序的函数,但不是很会用,所以并没有用自带的调度程序,而蓝牙程序中不能长时间被其他程序占用,不然会丢失蓝牙连接,所以我没有用延时,使用的定时器计时

int led_cnt=0;
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void TMR0_IRQHandler(void) // TMR0 定时中断
{
    if(TMR0_GetITFlag(TMR0_3_IT_CYC_END))
    {
        TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志

        if(delay_cnt[0]>0){
        	delay_cnt[0]--;
        	if(delay_cnt[0]==0){
        		run_flag[0]=1;
        	}
        }
        if(delay_cnt[1]>0){
        	delay_cnt[1]--;
        	if(delay_cnt[1]==0){
        		run_flag[1]=1;
        	}
        }
    	led_cnt++;
    	if(led_cnt%15==0 && stick_func==0) GPIOB_InverseBits(GPIO_Pin_4);//反转
    	else if(led_cnt%50==0 && stick_func==1) GPIOB_InverseBits(GPIO_Pin_4);//反转
//    	if(led_cnt==150){
//    		usb_flag =0;
//    	}
    }
}

定时器中断中有两个计时变量,主要负责USB数据发送和ADC采集

最后是主循环,

里面就是蓝牙、USB和ADC的调用程序

__attribute__((section(".highcode")))
__attribute__((noinline))
void Main_Circulation()
{
	memset(run_flag,1,10);
	uint8_t i=0;
    while(1)
    {
//    	mDelaymS(100);
//    	if(usb_flag == 0){
//    		TMR0_ITCfg(DISABLE, TMR0_3_IT_CYC_END);
    		TMOS_SystemProcess();//处理蓝牙
//    	}else{
    		TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
//    	}
    	if(run_flag[0]&&usb_flag!=0){//处理usb
    		run_flag[0]=0;
    		switch(run_index[0]){
    		case 0:
    			if(stick_func == 0)
    			DevHIDMouseReport(key2_down<<1|key1_down,(int)(abs(lr_value)<=15 ? lr_value/2 : lr_value > 0 ? lr_value*1.57-17.14:lr_value*1.57+17.14),(int)(abs(ud_value<=15) ? ud_value/2 : ud_value >0 ?ud_value*1.57-17.14 : ud_value*1.8+13));
    			else DevHIDMouseReport(key2_down<<1|key1_down,0,0);
    			if(abs(ud_value)==0){
    				delay_cnt[0]=1;//10ms
    				run_index[0]=0;//摇杆没有值就只反馈鼠标按键
    			}else{
    				delay_cnt[0]=1;//10ms
    				run_index[0]++;//摇杆有值再进行下一步
    			}
    			break;
    		case 1:
    			DevHIDMouseReport(0x00,0,0);
    			delay_cnt[0]=1;//10ms
    			run_index[0]++;
    			break;
    		case 2:
    			if(stick_func == 1){
    				DevHIDKeyReport(ud_value<0 ? 0x52 : ud_value > 0 ? 0x51 : 0);//上下方向键,鼠标滚轮在手机抖音横屏翻页时会有问题
    				if(abs(ud_value)<15)delay_cnt[0]=20;
    				else delay_cnt[0]=20-abs(ud_value)/2;
    				run_index[0]++;
    			}else{
    				delay_cnt[0]=1;//10ms
    				run_index[0]=0;//结束
    			}
    			break;
    		case 3:
    			DevHIDKeyReport(0x00);
    			delay_cnt[0]=1;
    			run_index[0]=0;
    			break;
    		case 4:
    			delay_cnt[0]=1;
    			run_index[0]=0;
    			break;
    		default:
    			run_index[0]=0;
    			delay_cnt[0]=10;
    			break;
    		}
    	}
    	if(run_flag[1]){//处理ADC
    		run_flag[1]=0;
    		switch(run_index[1]){
    		case 0:

    			delay_cnt[1]=10;//100ms
    			run_index[1]++;
    			ADC_ChannelCfg(0);
				adcBuff[0] = ADC_ExcutSingleConver(); //
			    ADC_ChannelCfg(1);
				adcBuff[1] = ADC_ExcutSingleConver(); //
				if(abs(start_lr_adc-adcBuff[0])>death_value){
					lr_value = (adcBuff[0]-start_lr_adc)/div_times;
				}else
					lr_value = 0;
				if (abs(start_ud_adc - adcBuff[1]) > death_value) {
					ud_value = (start_ud_adc - adcBuff[1])/div_times;
				} else
					ud_value = 0;
				if(switch_flag==1){
					if(!key3_down){
						if(stick_func==0)
							stick_func = 1;
						else stick_func = 0;
						switch_flag = 0;
					}
				}
				PRINT("%d %d stick_func %d\n", lr_value,ud_value,stick_func); // 注意:由于ADC内部偏差的存在,当采样电压在所选增益范围极限附近的时候,可能会出现数据溢出的现象
    			break;
    		case 1:

    			delay_cnt[1]=2;//20ms
    			run_index[1]=0;
    			break;
    		default:
    			run_index[1]=0;
    			break;
    		}
    	}

    }
}

蓝牙数据发送时对数据稍稍做了处理,摇杆幅度小时放慢速度,幅度大时加快速度

hidEmuSendMouseReport(mouse_button ,(int)(abs(lr_value)<=15 ? lr_value/2 : lr_value > 0 ? lr_value*1.57-17.14:lr_value*1.57+17.14), (int)(abs(ud_value<=15) ? ud_value/2 : ud_value >0 ?ud_value*1.57-17.14 : ud_value*1.8+13));//根据摇杆上下限调整系数,主要是小幅度时减半,大幅度时增大

<think>好的,用户现在问的是关于CH32F203开发的硬件环境。首先,我需要确认CH32F203是什么型号。查一下,CH32F203是南京沁恒微电子推出的一款基于ARM Cortex-M3内核的微控制器,主频最高144MHz,内置高速Flash和SRAM,适用于工业控制、物联网等领域。 用户之前问过NDIR技术的应用领域,可能现在转向具体的硬件开发,可能是想做一个实际项目,比如环境监测或者工业控制设备,需要用到这个MCU。所以用户可能是一位工程师或者学生,正在准备开发一个项目,需要了解搭建开发环境的步骤和所需硬件工具。 接下来,我需要整理CH32F203开发所需的硬件环境。通常包括开发板、调试工具、电源、外设模块、软件环境等。其中开发板部分,官方有评估板,比如CH32F203C8T6核心板,或者第三方开发板。需要提到这些开发板的基本配置,比如主控型号、封装、内存大小等。 调试工具方面,CH32F203支持SWD接口,常用的调试器有WCH-Link,这个需要特别说明,因为沁恒自家的调试工具可能和其他ST-Link或者J-Link有所不同。另外,还要提到USB转串口工具,比如CH340,用于串口通信。 电源部分,需要说明开发板的供电方式,比如USB供电或者外部电源,电压要求,比如3.3V。外设模块可能包括LED、按键、显示屏、传感器模块等,用于功能验证。 软件环境方面,需要提到IDE,比如MounRiver Studio,这是沁恒推荐的开发环境,基于Eclipse,支持C/C++开发。还有编译器,比如GCC,以及调试工具WCH-Link Utility。可能需要说明如何安装驱动,如何配置工程等。 然后要考虑用户可能遇到的问题,比如调试器的选择,是否兼容其他品牌,或者开发环境搭建中的常见错误。比如,使用WCH-Link需要注意固件版本,或者驱动安装是否正确。 另外,用户可能想知道如何开始一个简单的项目,比如点灯程序,所以步骤部分需要详细,从硬件连接到软件配置,编译下载,调试等流程。 最后,还要提到扩展硬件,比如如果需要更多外设或通信接口,可能需要额外的模块,比如WiFi、蓝牙、以太网等,这些模块如何与CH32F203连接。 需要确保回答结构清晰,分点说明,让用户能够一步步搭建起硬件环境。同时,要使用中文,避免专业术语过于晦涩,必要时解释缩写,比如SWD、IDE等。 检查是否有遗漏的部分,比如是否提到操作系统的兼容性,比如Windows下的驱动安装,或者Linux下的支持情况。可能用户是在不同的操作系统下开发,需要简要说明。 总结来说,回答需要涵盖开发板、调试工具、电源、外设、软件环境、开发步骤以及常见问题,确保用户能够根据指南顺利开始CH32F203的开发工作。</think>以下是关于CH32F203微控制器开发的硬件环境详细介绍: --- ### 一、核心开发硬件组件 #### 1. **开发板选择** - **官方评估板**: - 型号:CH32F203C8T6核心板 - 主控:CH32F203C8T6(LQFP48封装) - 配置:128KB Flash + 20KB SRAM,支持USB 2.0全速接口 - 外设:板载LED、按键、USB接口、SWD调试接口 - **第三方开发板**: - 例如:WCH拓展板(集成CAN、以太网PHY等工业接口) #### 2. **调试下载工具** - **WCH-Link**(专用调试器): - 支持SWD协议,兼容ARM Cortex-M3内核 - 双模式:默认调试模式(需短接VCC跳线) + 串口模式 - **其他兼容工具**: - J-Link(需安装WCH补丁) - ST-Link(通过OpenOCD配置适配) #### 3. **电源供应** - **供电方式**: - USB供电:5V/500mA(通过Type-C接口) - 外部电源:3.3V直连(需注意电压纹波<50mV) - **功耗监测**:建议配备数字万用表(测量运行/休眠模式电流) #### 4. **外设扩展模块** - 基础模块:OLED屏幕(I2C接口)、按键矩阵、蜂鸣器 - 通信模块:ESP8266 WiFi模组(AT指令)、CAN总线收发器(如TJA1050) - 传感器:温湿度传感器(DHT11)、加速度计(MPU6050) --- ### 二、软件环境配置 #### 1. **集成开发环境(IDE)** - **MounRiver Studio**(WCH官方推荐): - 基于Eclipse框架,内置GCC编译器链 - 支持工程模板生成(如GPIO、UART、USB HID等) - **Keil MDK**: - 需手动安装CH32F203器件支持包(从WCH官网下载) #### 2. **驱动安装** - WCH-Link驱动:通过MounRiver Studio自动安装 - USB串口驱动:安装CH340/CH341驱动程序(用于UART通信) #### 3. **代码库与工具链** - 标准外设库:WCH提供的`ch32f20x.h`头文件及外设驱动库 - 调试工具:WCH-Link Utility(固件升级/擦除Flash) --- ### 三、硬件连接示意图 ```plaintext [PC] ↔ [WCH-Link] │ (SWCLK/SWDIO) ↓ [CH32F203开发板] ├── USB ↔ PC(用于USB设备开发) ├── UART_TX → CH340_RX(调试信息输出) └── GPIO → 外设模块(如LED/传感器) ``` --- ### 四、开发流程示例(以LED闪烁为例) #### 步骤1:硬件连接 - 将WCH-Link的SWD接口(SWCLK/SWDIO/GND)与开发板对应引脚连接 - 开发板通过USB供电 #### 步骤2:工程创建 1. 打开MounRiver Studio,选择`File → New → WCH Project` 2. 选择芯片型号`CH32F203C8T6`,勾选`GPIO`库 #### 步骤3:代码编写 ```c #include "ch32f20x.h" void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStruct); } int main(void) { GPIO_Config(); while(1) { GPIO_WriteBit(GPIOC, GPIO_Pin_13, !GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13)); Delay_Ms(500); } } ``` #### 步骤4:编译与下载 - 点击`Build`生成`HEX`文件 - 连接WCH-Link,点击`Download`烧录程序 --- ### 五、调试技巧与常见问题 #### ▨ **调试技巧** - **实时变量监控**:使用`Live Watch`功能监控全局变量 - **HardFault定位**:通过`Call Stack`查看异常时的寄存器状态 #### ▨ **常见问题** 1. **WCH-Link无法识别**:检查USB驱动是否安装,尝试短接VCC选择调试模式 2. **程序无法运行**:确认启动模式(BOOT0引脚需接地) 3. **USB枚举失败**:检查DP/DM线序,确认时钟配置(需72MHz PLL) --- 如需特定外设(如USB、CAN)的硬件设计注意事项,可进一步说明需求!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山间朝暮-CanEve

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值