打印
[MM32软件]

灵动微电子MM32F5330测评+用开发板玩霸王龙铬恐龙小游戏

[复制链接]
939|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 xiaoqi976633690 于 2024-7-1 11:42 编辑

#申请原创#

灵动微电子MM32F5330测评+教开发板玩霸王龙-铬恐龙小游戏
一、实验介绍


霸王龙恐龙 (谷歌恐龙游戏) https://dinorunner.com/zh/- 当没有互联网时,Chrome 浏览器中隐藏游戏的副本。 按空格键开始。 使用空格键或向上箭头和向下箭头 (↓) 跳跃恐龙以躲避。
这里我们用MM32F5333开发板的 USB功能+ADC实现障碍物检测和发送跳跃指令让单片机自己玩


二、实验目的
使用MM32F5333开发板通过USB HID与计算机通信发送keyboard键值,使用ADC 连接光敏电阻监测光线强度,来判断前方是否有障碍物。
将光敏电阻连接至开发板的ADC,光敏接收面对着屏幕实时检测游戏背景和障碍物的亮度,由于背景和障碍物的亮度不同,当检测到障碍物时通知usb hid发送空格键给电脑实现恐龙跳跃。




三、代码实现
1.usb 代码
由于官网的demo里面没有USB相关的代码,我们需要去https://mindsdk.mindmotion.com.cn/sdk/sdk-create/ 生成基于tinyusb的USB DEMO。
找到demo_apps\tinyusb\tud_hid_keyboard 这个就是USB HID 的demo。
不做任何修改的demo是不断的往电脑发送A键,在while死循环里我们需要删掉原始代码,只保留tud_task();。
新建一个键值发送函数
void SEND_KEY_CODE(uint8_t key)
{
        uint8_t keycode[6] = { 0 };
                                keycode[0] = key;
                                if(tud_hid_ready())
                                {
                                         tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);
                                }
      

}



键盘发送给PC的数据每次8个字节

/// Standard HID Boot Protocol Keyboard Report.
typedef struct TU_ATTR_PACKED
{
  uint8_t modifier;  //BYTE1
  uint8_t reserved; //BYTE12
  uint8_t keycode[6]; //BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
} hid_keyboard_report_t;

BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
定义分别是:
BYTE1 –
|–bit0: Left Control是否按下,按下为1
|–bit1: Left Shift 是否按下,按下为1
|–bit2: Left Alt 是否按下,按下为1
|–bit3: Left GUI 是否按下,按下为1
|–bit4: Right Control是否按下,按下为1
|–bit5: Right Shift 是否按下,按下为1
|–bit6: Right Alt 是否按下,按下为1
|–bit7: Right GUI 是否按下,按下为1
BYTE2 – 保留位
BYTE3–BYTE8 – 这六个为普通按键

keycode[6] 对应BYTE3–BYTE8 – 这六个为普通按键

2.ADC初始化&ADC通道值获取


adc初始化
void ADC_Configure(void)
{
    /* pins and clock are already in the pin_init.c and clock_init.c. */

    /* setup the converter. */
    ADC_Init_Type adc_init;
                GPIO_Init_Type gpio_init;
        
                RCC_SetADCCalibClockDiv(ADC1, 48);
          RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA, true);
    RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOA);
          RCC_EnableAPB2Periphs(RCC_APB2_PERIPH_ADC1, true);
    RCC_ResetAPB2Periphs(RCC_APB2_PERIPH_ADC1);
        
    adc_init.Resolution = ADC_Resolution_Alt0;
    adc_init.ConvMode = ADC_ConvMode_SeqOneTime;
    adc_init.Align = ADC_Align_Right;
    adc_init.SingleDiffMode = ADC_SingleDiffConvMode_SingleEnd; /* single-ended channel conversion mode. */
    adc_init.SingleVolt = ADC_SingleConvVref_External;  /* internal reference voltage as the reference voltage for single-ended conversion. */
    ADC_Init(BOARD_ADC_PORT, &adc_init);

    ADC_Enable(BOARD_ADC_PORT, true); /* power on the converter. */

                //转换通道数配置3,
    ADC_EnableSeqSlot(BOARD_ADC_PORT, 3,2 );

    /* set channel sample time. */
    ADC_SetChnSampleTime(BOARD_ADC_PORT, 2, ADC_SampleTime_Alt7);

            /* PA0 - ADC1 channel_0. */
    gpio_init.Pins  = GPIO_PIN_2;
    gpio_init.PinMode  = GPIO_PinMode_In_Analog;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);

}
adc通道获取函数
uint32_t app_adc_run_conv(void)
{
    uint32_t data;
    uint32_t flags;
    uint32_t adc_channel; /* keep the actual hardware conversion channel number. */

    /* software tirgger the conversion. */
    ADC_DoSwTrigger(BOARD_ADC_PORT, true);

    /* wait while the conversion is ongoing. */
    while( 0u == (ADC_GetStatus(BOARD_ADC_PORT) & ADC_STATUS_CONV_SEQ_DONE) )
    {}

    ADC_ClearStatus(BOARD_ADC_PORT, ADC_STATUS_CONV_SEQ_DONE);

    data = ADC_GetConvResult(BOARD_ADC_PORT, &adc_channel, &flags);

    if (0u == (flags & ADC_CONV_RESULT_FLAG_VALID) )
    {
        data = 0u; /* the data is unavailable when the VALID flag is not on. */
    }

    return data;
}
ADC折腾了半天这个和官网的库不是一个东西,而且没有官网的库好用。

main函数
/*------------- MAIN -------------*/
int main(void)
{
  BOARD_Init();
  tusb_init();
        InitPins();
        ADC_Configure();
        InitDebugConsole();
  while (1)
  {
                //getchar();
    tud_task();
                ADC_DoAutoCalib(BOARD_ADC_PORT); /* get calibration factors using hardware self-calibration. */        
                if(GPIO_ReadInDataBit(GPIOC,GPIO_PIN_5)==0)
                {
                        SEND_KEY_CODE(HID_KEY_B);
                }               
                if((unsigned)app_adc_run_conv()< 1620u)//障碍物检测
                {
                        GPIO_WriteBit(GPIOC, GPIO_PIN_7, 1);        
                        GPIO_WriteBit(GPIOC, GPIO_PIN_6, 1);
                        printf("adc=%u\r\n", (unsigned)app_adc_run_conv());
                        if((unsigned)app_adc_run_conv()< 1620u)
                        {
                                
                                SEND_KEY_CODE(HID_KEY_SPACE);
                                
                        }
                        
                }
                else
                        {
                                GPIO_WriteBit(GPIOC, GPIO_PIN_7, 0);        
                                GPIO_WriteBit(GPIOC, GPIO_PIN_6, 0);
                                tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL);//释放按键
                        }
               

        //        printf("adc_val= %u\r\n", (unsigned)app_adc_run_conv());
  }

}


四、实验演示

https://www.bilibili.com/video/BV1Yg3ceLEfR/


五、开发心得
1.https://mindsdk.mindmotion.com.cn/sdk/sdk-create/ 生成的库和https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_performance/mm32f5330/ 的库不兼容希望官方整合成一套库。mindsdk的库不是很容易上手。
2.这个程序还有优化的空间,例如可以让小恐龙在没有障碍物的时候为趴下状态,这需要单片机一直发送 ↓  检测到障碍物后再释放站起来再跳跃。以及再加一个传感器检测恐龙的颜色可以实现背景变换后依旧可以识别。





使用特权

评论回复
沙发
[鑫森淼焱垚]| | 2024-8-1 14:03 | 只看该作者
点赞

使用特权

评论回复
板凳
gouguoccc| | 2024-8-2 08:03 | 只看该作者
解压趣味小游戏

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

191

帖子

2

粉丝