大家好,我是板哥,最近社区上线了【硬核玩电·创意DIY】活动,欢迎各位电子界朋友们,以电子为笔,以创意为墨来社区交个朋友。
本次活动参加即有奖励。更有开发板大礼包(多款)+京东自营购物金等您来拿!详见文末

所以本期活动一定不会落下必须得好好参与一下的。所以一开始参与该活动自己想的宗旨就是:要有技术分享,又要有乐趣,可复制,可以作为学习资料。所以希望找一个合适的主题IDEA,可以详细的分享整个DIY过程。
直到有一天,上班比较早,到了公司停下车,就在车里休息下。但是呢又没什么可做的,就仰躺着发呆,突然看到了行车记录仪,脑瓜子闪现了一个念头...行车记录仪有显示,是不是可以将其改造为一个小的游戏机。在这种等对象,接小孩,等等无比聊赖的时候,如果能来一把坦克大战,那将是多么惬意的事情。
这个想法简直太帅了,就它了,说干就干!
整体设计
先来设计下整体方案,刚好在之前的拆解活动中也分享了拆解的一个行车记录仪,设备还闲置着呢,这不就派上用场了。
还记得有网友都在评论,这是电子垃圾,不过垃圾也可以变废为宝!!!这就是嵌入式开发者的乐趣。
整体设计如下,阴影部分是需要设计的,即需要设计两块板子。
1. 无线手柄
需要使用电池供电,所以需要设计电池充电,自动切换电源,开关机等电源管理功能。
另外就是按键采集部分和控制板通过无线连接,可以使用蓝牙或者其他无线模块。

尽量考虑不影响原来行车记录仪的功能,游戏机需要使用记录仪的屏幕作为显示,所以考虑增加一个switch,可以切换屏幕接记录仪还是接控制板。
需要实现文件系统用于存储游戏文件。
总结
有了IDEA就开始干了,在年前就完成了手柄和控制板的硬件设计,板子也焊接好了,趁着过年把软件完成。
本着寓教于乐的精神,后续会连载文章,尽可能详细的分享每一个步骤和细节,这样本系列文章也可以作为嵌入式初学者实践的一个案例来参考学习。
第一部分:无线手柄硬件设计
硬件已经开源,地址如下: https://oshwhub.com/qinyunti/key-w, 本文介绍手柄硬件的设计过程。

整体结构如下,基于PY32F002B的MCU主控,包括电源管理模块,无线模块用于和控制板通讯,按键采集部分。

这里MCU选用了py32f002b,因为它真的很便宜! 大概5毛钱一颗,32位Cortex-M0,开发起来也很方便,开发小的东西很好用。


一个LED指示灯
选择无线模块或者蓝牙模块用于和主控通讯。


8路按键采集,使用IIC接口的芯片PCF8574采集

主要包括以下部分
USB供电充电,以及转ttl串口,可以直接调试蓝牙模块。
USB和电池供电切换电路
充电部分
开关机控制部分
5V转3V3电源

嘉立创在线EDA可以直接下单,注意下单前一定要进行DRC检测避免错误。



然后个人习惯是先焊接MCU和最小系统,然后再按照模块焊接完。
焊接完之后图片如下


测试的话同样的先确认电源没有短路等情况,然后上电,确认电源输出是否正确,
然后连接JLINK看是否能识别芯片,这些都OK基本,后面就是软件调试了。
总结
以上分享了手柄的硬件设计,以及打样焊接调试过程,一点小经验,焊接时随时确认电源。
第二部分:无线手柄软件开发
前面我们完成了手柄的硬件设计与调试,现在来分享详细的软件开发过程。
软件已经开源见:https://github.com/qinyunti/py32f002b-key.git。本着寓教于乐的精神,尽可能详细分享整个过程,本文也可以作为py32f002b的开发参考。
开发环境搭建
我这里基于MDK 5.40,编译器版本6. MDK的安装就不再赘述。
1. 下载手册和SDK
从以下官网地址https://www.py32.org/mcu/PY32F002Bxx.html下载相关资料

其他资料可以参考
https://pan.baidu.com/s/1GJoXbWn9oOyeqGn6Igg5DA?pwd=6688&_at_=1737128105692#list/path=%2F%E8%B5%84%E6%96%99%E4%B8%8B%E8%BD%BD%2FMCU%E8%B5%84%E6%96%99%2FPY32%E7%B3%BB%E5%88%97%E5%8D%95%E7%89%87%E6%9C%BA
2. 安装MDK支持包
可以如下MDK中在线安装

Project->New uVision Project...
选择目录,输入工程名保存





Ctrl+S保存
保存为main.c






看到识别到了芯片



D:\Keil_v5\ARM\Flash
此时点击ADD就可以看到上述算法


4. 添加驱动库
将git上下载的固件库的PY32F002B_HAL_Driver复制到自己的工程,并添加
点击Target右键,添加Group

双击Driver,添加所有c和h文件


py32f002b_hal_conf.h到自己的工程,同样添加其所在路径到头文件包含路径。
OPT编程方法
硬件上PC0控制了一个LED
默认PC0为复位功能,可以修改为IO功能。
需要修改opt,以下以修改PC0为IO为例介绍。



文件py32f002b_OPT.s添加到工程,内容为
;/*****************************************************************************/;/* py32f002b_OPT.S: y32f002b Flash Option Bytes */;/*****************************************************************************/;/* <<< Use Configuration Wizard in Context Menu >>> */;/*****************************************************************************/;/* This file is part of the uVision/ARM development tools. */;/* Copyright (c) 2005-2008 Keil Software. All rights reserved. */;/* This software may only be used under the terms of a valid, current, */;/* end user licence from KEIL for a compatible version of KEIL software */;/* development tools. Nothing else gives you the right to use this software. */;/*****************************************************************************/;// <e> Flash Option BytesFLASH_OPT EQU 0;// </e> IF FLASH_OPT <> 0 AREA |.ARM.__AT_0x1FFF0080|, CODE, READONLY DCB 0xAA, 0xDE, 0x55, 0x21 DCB 0x0B, 0x00, 0xF4, 0xFF DCB 0x00, 0x00, 0xFF, 0xFF DCB 0x3F, 0x00, 0xC0, 0xFF ENDIF END



从官网下载PY32OptionBytesConfig_x64.exe生成
https://py32.org/tool/PY32_OptionBytesConfig.html


以上之后直接点击d就会和程序一起下载。
下载完成之后这里不勾选,下次就不会再下载opt了。

以上修改opt之后,pc0就变为了IO功能,用于驱动LED
初始化
void led_init(void){ GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOC_CLK_ENABLE(); /* Enable GPIOA clock */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; /* Push-pull output */ GPIO_InitStruct.Pull = GPIO_PULLUP; /* Enable pull-up */ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; /* GPIO speed */ /* GPIO initialization */ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); }
然后HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);就可以反转控制LED。
串口驱动/蓝牙模块控制
我们接收中断+FIFO实现串口接收,发送使用查询方式。
FIFO的实现见公众号文章。
串口驱动实现见公众号文章
代码见uart.c/h,fifo.c/h
代码考虑了可移植性,可以方便的移植。

void uart_init(uint32_t baud){ UART_HandleTypeDef huart; GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); /* Enable GPIOA clock */ __HAL_RCC_USART1_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; /* Push-pull output */ GPIO_InitStruct.Pull = GPIO_PULLUP; /* Enable pull-up */ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; /* GPIO speed */ GPIO_InitStruct.Alternate = GPIO_AF1_USART1; /* PA6 AF1 USART_TX*/ /* GPIO initialization */ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //LL_USART_InitTypeDef USART_InitStruct; //USART_InitStruct.BaudRate = baud; //USART_InitStruct.DataWidth = 16; //USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE; //USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_8; //USART_InitStruct.Parity = LL_USART_PARITY_NONE; //USART_InitStruct.StopBits = LL_USART_STOPBITS_1; //USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX; //LL_USART_Init(USART1, &USART_InitStruct); //LL_USART_EnableIT_RXNE(USART1); huart.Instance = USART1; huart.Init.BaudRate = baud; huart.Init.WordLength = UART_WORDLENGTH_8B; huart.Init.StopBits = UART_STOPBITS_1; huart.Init.Parity = UART_PARITY_NONE; huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart.Init.Mode = UART_MODE_TX_RX; huart.Init.OverSampling = UART_OVERSAMPLING_8; HAL_UART_Init(&huart); //24000000/115200 = 208.3333 //USART1->BRR = (208ul<<4) + 5; __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE); HAL_NVIC_SetPriority(USART1_IRQn,1,1); HAL_NVIC_EnableIRQ(USART1_IRQn);}
void uart_rx_cb(uint8_t* buff, uint32_t len){ fifo_in(&s_uart_fifo_dev, buff, len);}void USART1_IRQHandler(void){ uint8_t ch; ch = LL_USART_ReceiveData8(USART1); uart_rx_cb(&ch, 1);}
uint32_t uart_read(uint8_t* buffer, uint32_t len){ uint32_t rlen; CriticalAlloc(); EnterCritical(); rlen = fifo_out(&s_uart_fifo_dev, buffer, len); ExitCritical(); return rlen;}
uint32_t uart_send(uint8_t* buffer, uint32_t len){ for(uint32_t i=0;i<len;i++) { while(LL_USART_IsActiveFlag_TXE(USART1) == 0); LL_USART_TransmitData8(USART1,buffer); } return len;}
蓝牙模块使用AT指令详见模块手册即可。
IIC驱动与PCF8574按键采集
IIC直接使用IO模拟的方式,因为有现成的代码,简单方便。
代码如下

Pcf8574驱动,设计为完全独立的模块,只依赖iic操作,无需任何修改完全可移植。具体操作参考手册即可。

static io_iic_dev_st iic_dev={ .scl_write = io_iic_scl_write_port, .sda_write = io_iic_sda_write_port, .sda_2read = io_iic_sda_2read_port, .sda_read = io_iic_sda_read_port, .delay_pf = io_iic_delay_us_port, .init = io_iic_init_port, .deinit = io_iic_deinit_port, .delayus = 1,};
pcf8574_dev_st pcf8574_dev={ .start = pcf8574_iic_start_port, .stop = pcf8574_iic_stop_port, .read = pcf8574_iic_read_port, .write = pcf8574_iic_write_port, .init = pcf8574_iic_init_port, .deinit = pcf8574_iic_deinit_port, .addr = 0,};
在main.c中初始化 HAL_Init(); HAL_Delay(1000); led_init(); key_init(); uart_init(115200);蓝牙初始化#define AT_CONN "AT+CONN=D2BC14D9F46B\r\n" uart_send((uint8_t*)AT_CONN,strlen(AT_CONN)); HAL_Delay(1000);发送该命令连接从蓝牙,进入透传模式,D2BC14D9F46B为从模块的地址,具体获取参考蓝牙模块的规格书。按键和LED使用时间控制 uint32_t led_pre_ts = 0; uint32_t led_cur_ts = 0; uint32_t key_pre_ts = 0; uint32_t key_cur_ts = 0;LED1S反转一次 led_pre_ts = HAL_GetTick(); key_pre_ts = HAL_GetTick(); while (1){ led_cur_ts = HAL_GetTick(); key_cur_ts = HAL_GetTick(); if(diff_u32(led_pre_ts, led_cur_ts) >= LED_PERIOD){ led_pre_ts = led_cur_ts; HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0); }按键20ms获取一次并发送 if(diff_u32(key_pre_ts, key_cur_ts) >= KEY_PERIOD){ key_pre_ts = key_cur_ts; key_read(&key_now); s_key_buf[2] = key_now; s_key_buf[3] = ~key_now; uart_send(s_key_buf,sizeof(s_key_buf)); }
测试见视频,先蓝牙从模块接电脑,可以看到每一个按键都正确。
以上详细分享了py32f002b的开发过程,包括串口,LED控制,按键等模块的驱动。可以作为py32ff002b的入门开发参考。
手柄硬件 https://oshwhub.com/qinyunti/key-w
手柄软件 https://github.com/qinyunti/py32f002b-key.git
原帖地址:https://mbb.eet-china.com/forum/topic/148531_1_1.html
硬核玩电/DIY!赢开发板大礼包!
亲爱的电子工程师、硬件极客、电子爱好者、社区的家人们:
这个夏天,以电子为笔,以创意为墨——来面包板社区造点会"跳动"的电子DIY吧!我们给大家准备了开发板大礼包+京东自营购物礼金!等您来拿哦!
基础福利:所有参与者可领取2000 E币(可在面包板社区兑换商城使用)。
活动奖项:
硬核奖(1名):开发板大礼包(知名品牌开发板2块【如芯驿、STM32等】+其他开发板1块,市场价不低于1500元) +1000元京东自营商城购物金。
创意奖(1名):开发板礼包(品牌开发板2块【STM32、灵动微等】,市场价不低于500元);+500元京东自营商城购物金。
人气奖(1名):开发板礼包(品牌开发板2块【STM32、灵动微等】,市场价不低于500元)+500元京东自营商城购物金。
达人奖(5名):奖励200元京东自营购物金。
优秀作品奖:内容最生动、故事性最强的作品在面包板社区微信公众号阅读量过万的内容,每篇奖励1000E币,不限篇数。
注:更多详情请访问https://mbb.eet-china.com/forum/topic/153762_1_1.html
点击阅读原文,了解活动详情!