本帖最后由 xiaoqi976633690 于 2024-5-5 17:20 编辑
#申请原创# #有奖活动# #申请开发板# 一、项目描述
1、项目介绍 该项目基于AT-START-F405 V1.0 板载了AT32F405RCT7-7芯片,外设配置LED灯,按钮,两组USB type-C和Type-A的连接器。 并自带自带嵌入式调试/烧录工具AT-Link-EZ。 外围只需要简单的IR模块+IR遥控就可以搭建一个简易的基于红外控制的usb键盘。 2、设计思路 a.红外接收部分基于TIMEER3捕获红外NEC解码。 b.USB部分使用USB device 配置为 keyboard。 3、硬件 a.AT-START-F405 V1.0 b.IR接受模块 c.IR多媒体遥控
二、软件流程图及各功能对应的主要代码片段及说明 1、流程图 2、代码片段说明 NEC红外协议编码原理这里不做过多解释。 定时器初始化要特别注意分频系数 GPIO复用PB5 MUX1 1、初始化红外 void infrared_receiver_init(void)
{
gpio_init_type gpio_init_struct;
tmr_input_config_type tmr_input_config_struct;
crm_clocks_freq_type crm_clock_freq;
/* init infrared receiver fifo */
infrared_receiver_fifo_init();
/* enable tmr3/gpioa clock */
crm_periph_clock_enable(IR_TMR_CLK, TRUE);
crm_periph_clock_enable(IR_GPIO_CLK, TRUE);
/* timer input pin Configuration */
gpio_init_struct.gpio_pins = IR_GPIO_PIN;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(IR_GPIO_PORT, &gpio_init_struct);
gpio_pin_mux_config(IR_GPIO_PORT, IR_GPIO_PINS_SOURCE, IR_GPIO_MUX);
/* get the system frequency value */
crm_clocks_freq_get(&crm_clock_freq);
/* tmr counter mode configuration */
// tmr_base_init(IR_TMRx, 6000, crm_clock_freq.apb1_freq / 1000000);
tmr_base_init(IR_TMRx, 6000,215);//改为分频215
tmr_cnt_dir_set(IR_TMRx, TMR_COUNT_UP);
/* configure tmr channel to get clock signal */
tmr_input_config_struct.input_channel_select = IR_TMR_CHANNEL;
tmr_input_config_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;
tmr_input_config_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;
tmr_input_channel_init(IR_TMRx, &tmr_input_config_struct, TMR_CHANNEL_INPUT_DIV_1);
/* enable capture interrupt */
tmr_interrupt_enable(IR_TMRx, IR_TMR_CHANNEL_INT, TRUE);
/* disable overflow interrupt */
tmr_interrupt_enable(IR_TMRx, TMR_OVF_INT, FALSE);
/* interrupt nvic init */
nvic_irq_enable(IR_TMR_IRQn, 1, 0);
/* enable tmr */
tmr_counter_enable(IR_TMRx, TRUE);
}
2、中断接收解码void infrared_receiver_data_deal(void)
{
uint32_t value;
/* input capture event occurs */
if(tmr_flag_get(IR_TMRx, IR_TMR_CHANNEL_FLAG) != RESET)
{
/* clear input capture flag */
tmr_flag_clear(IR_TMRx, IR_TMR_CHANNEL_FLAG);
/* clear overflow flag */
tmr_flag_clear(IR_TMRx, TMR_OVF_FLAG);
/* enable overflow interrupt */
tmr_interrupt_enable(IR_TMRx, TMR_OVF_INT, TRUE);
/* rising edge capture */
if(IR_GPIO_READ())
{
/* clear the counter */
tmr_counter_value_set(IR_TMRx, 0);
/* configure capture mode as falling edge capture */
tmr_output_channel_polarity_set(IR_TMRx, IR_TMR_CHANNEL, TMR_POLARITY_ACTIVE_LOW);
}
/* falling edge capture */
else
{
/* get capture counter */
value = tmr_channel_value_get(IR_TMRx, IR_TMR_CHANNEL);
/* configure capture mode as rising edge capture */
tmr_output_channel_polarity_set(IR_TMRx, IR_TMR_CHANNEL, TMR_POLARITY_ACTIVE_HIGH);
/* received start code */
if((value > 4200) && (value < 4700))
{
at32_led_toggle(LED3);
ir_data = 0;
}
/* received repeat code */
else if((value > 2000) && (value < 2600))
{
/* analysis data */
infrared_receiver_key_deal(ir_data);
}
/* received bit 0 */
else if((value > 300) && (value < 800))
{
ir_data <<= 1;
}
/* received bit 1 */
else if((value > 1400) && (value < 1800))
{
ir_data <<= 1;
ir_data |= 1;
}
}
}
/* overflow event occurs, 6ms , receive complete */
else if(tmr_flag_get(IR_TMRx, TMR_OVF_FLAG) != RESET)
{
/* clear overflow flag */
tmr_flag_clear(IR_TMRx, TMR_OVF_FLAG);
/* disable overflow interrupt */
tmr_interrupt_enable(IR_TMRx, TMR_OVF_INT, FALSE);
/* configure capture mode as rising edge capture */
tmr_output_channel_polarity_set(IR_TMRx, IR_TMR_CHANNEL, TMR_POLARITY_ACTIVE_HIGH);
/* analysis data */
infrared_receiver_key_deal(ir_data);
}
}
3、USB device部分 USB基于examples\usb_device\keyboard 例程修改 在keyboard_class.c增加2个函数用于发送键值和组合按键
void keyboard_send(void *udev, uint8_t ascii_code)
{
usbd_core_type *pudev = (usbd_core_type *)udev;
keyboard_type *pkeyboard = (keyboard_type *)pudev->class_handler->pdata;
while(1)
{
if(pkeyboard->g_u8tx_completed == 1)
{
pkeyboard->g_u8tx_completed = 0;
pkeyboard->keyboard_buf[0] = 0;
pkeyboard->keyboard_buf[2] = ascii_code;
usb_keyboard_class_send_report(udev, pkeyboard->keyboard_buf, 8);
break;
}
}
}
/*
键盘发送给PC的数据每次8个字节:BYTE0 BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7。定义分别是:
BYTE0 --
|--bit0: Left Control 0x01
|--bit1: Left Shift 0x02
|--bit2: Left Alt 0x04
|--bit3: Left GUI(win键) 0x08
|--bit4: Right Control 0x10
|--bit5: Right Shift 0x20
|--bit6: Right Alt 0x40
|--bit7: Right GUI 0x80
*/
void keyboard_send_composite(void *udev,uint8_t BYTE0, uint8_t ascii_code)
{
usbd_core_type *pudev = (usbd_core_type *)udev;
keyboard_type *pkeyboard = (keyboard_type *)pudev->class_handler->pdata;
while(1)
{
if(pkeyboard->g_u8tx_completed == 1)
{
pkeyboard->g_u8tx_completed = 0;
pkeyboard->keyboard_buf[0] = BYTE0;
pkeyboard->keyboard_buf[2] = ascii_code;
usb_keyboard_class_send_report(udev, pkeyboard->keyboard_buf, 8);
break;
}
}
}
键盘键值 #define KEY_NULL 0x00
#define KEY_A 0x04 //A
#define KEY_B 0x05 //B
#define KEY_C 0x06 //C
#define KEY_D 0x07 //D
#define KEY_E 0x08 //E
#define KEY_F 0x09 //F
#define KEY_G 0x0A //G
#define KEY_H 0x0B //H
#define KEY_I 0x0C //I
#define KEY_J 0x0D //J
#define KEY_K 0x0E //K
#define KEY_L 0x0F //L
#define KEY_M 0x10 //M
#define KEY_N 0x11 //N
#define KEY_O 0x12 //O
#define KEY_P 0x13 //P
#define KEY_Q 0x14 //Q
#define KEY_R 0x15 //R
#define KEY_S 0x16 //S
#define KEY_T 0x17 //T
#define KEY_U 0x18 //U
#define KEY_V 0x19 //V
#define KEY_W 0x1A //W
#define KEY_X 0x1B //X
#define KEY_Y 0x1C //Y
#define KEY_Z 0x1D //Z
#define KEY_1 0x1E //1 !
#define KEY_2 0x1F //2 [url=home.php?mod=space&uid=72445]@[/url]
#define KEY_3 0x20 //3 #
#define KEY_4 0x21 //4 $
#define KEY_5 0x22 //5 %
#define KEY_6 0x23 //6 ^
#define KEY_7 0x24 //7 &
#define KEY_8 0x25 //8 *
#define KEY_9 0x26 //9 (
#define KEY_0 0x27 //0 )
#define KEY_ENTER 0x28
#define KEY_ESC 0x29
#define KEY_BACKSPACE 0x2A
#define KEY_TAB 0x2B
#define KEY_SPACE 0x2C
#define KEY_SUB 0x2D // - and _
#define KEY_EQUAL 0x2E // = and +
#define KEY_LEFT_BRACKET 0x2F // \[ and {
#define KEY_RIGHT_BRACKET 0x30 // \] and }
#define KEY_VERTICAL_LINE 0x31 // "\\" and |
#define KEY_WAVE 0x32 // \` and ~
#define KEY_SEMICOLON 0x33 // ; and :
#define KEY_QUOTE 0x34 // ' and "
#define KEY_THROW 0x35 // ~ and \`
#define KEY_COMMA 0x36 // , and <
#define KEY_DOT 0x37 // . and >
#define KEY_QUESTION 0x38 // / and ?
#define KEY_CAPS_LOCK 0x39
#define KEY_F1 0x3A
#define KEY_F2 0x3B
#define KEY_F3 0x3C
#define KEY_F4 0x3D
#define KEY_F5 0x3E
#define KEY_F6 0x3F
#define KEY_F7 0x40
#define KEY_F8 0x41
#define KEY_F9 0x42
#define KEY_F10 0x43
#define KEY_F11 0x44
#define KEY_F12 0x45
#define KEY_PRT_SCR 0x46
#define KEY_SCOLL_LOCK 0x47
#define KEY_PAUSE 0x48
#define KEY_INS 0x49
#define KEY_HOME 0x4A
#define KEY_PAGEUP 0x4B
#define KEY_DEL 0x4C
#define KEY_END 0x4D
#define KEY_PAGEDOWN 0x4E
#define KEY_RIGHT_ARROW 0x4F
#define KEY_LEFT_ARROW 0x50
#define KEY_DOWN_ARROW 0x51
#define KEY_UP_ARROW 0x52
#define KEY_PAD_NUMLOCK 0x53
#define KEY_PAD_DIV 0x54 // /
#define KEY_PAD_MUL 0x55 // \*
#define KEY_PAD_SUB 0x56 // -
#define KEY_PAD_ADD 0x57 // +
#define KEY_PAD_ENTER 0x58
4、main函数
int main(void)
{
__IO uint32_t delay_index = 0;
system_clock_config();
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
delay_init();
at32_board_init();
uart_print_init(115200);
infrared_receiver_init();
/* usb gpio config */
usb_gpio_config();
#ifdef USB_LOW_POWER_WAKUP
/* enable pwc and bpr clock */
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
button_exint_init();
usb_low_power_wakeup_config();
#endif
/* enable otg clock */
crm_periph_clock_enable(OTG_CLOCK, TRUE);
/* select usb 48m clcok source */
usb_clock48m_select(USB_CLK_HEXT);
/* enable otg irq */
nvic_irq_enable(OTG_IRQ, 0, 0);
/* init usb */
usbd_init(&otg_core_struct,
USB_SPEED_CORE_ID,
USB_ID,
&keyboard_class_handler,
&keyboard_desc_handler);
at32_led_on(LED2);
at32_led_on(LED3);
at32_led_on(LED4);
printf("IR_DATA=0x%08x\n", ir_data);
while(1)
{
if (infrared_receive(&ir_value) == SUCCESS)
{
printf("IR_DATA=0x%08x\n", ir_data);
switch(ir_data)
{
case 0x00ff02fd : //下箭头
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_DOWN_ARROW);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ffe21d : //下箭头
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_DOWN_ARROW);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ffa25d : //上箭头
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_UP_ARROW);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ff22dd : //上箭头
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_UP_ARROW);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ff906f : //老板键
keyboard_send(&otg_core_struct.dev,0);
keyboard_send_composite(&otg_core_struct.dev,0x08,0x07);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ffc23d : //暂停
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_SPACE);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ffe01f : //点赞
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_Z);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ffa857 : //收藏
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_C);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
case 0x00ff629d : //进入直播间或查看博主更多视频
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,KEY_F);
keyboard_send(&otg_core_struct.dev,0);
ir_data=0;
break;
}
}
if(at32_button_press() == USER_BUTTON)
{
if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_CONFIGURED)
{
keyboard_send(&otg_core_struct.dev,0);
keyboard_send(&otg_core_struct.dev,0x51);
keyboard_send(&otg_core_struct.dev,0);
//老板键win+D显示桌面
keyboard_send(&otg_core_struct.dev,0);
keyboard_send_composite(&otg_core_struct.dev,0x08,0x07);
keyboard_send(&otg_core_struct.dev,0);
// keyboard_send_string(&otg_core_struct.dev, (uint8_t *)" Keyboard Demo\r\n", 16);
}
/* remote wakeup */
if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_SUSPENDED
&& (otg_core_struct.dev.remote_wakup == 1))
{
usbd_remote_wakeup(&otg_core_struct.dev);
}
}
#ifdef USB_LOW_POWER_WAKUP
/* enter deep sleep */
if(((keyboard_type *)(otg_core_struct.dev.class_handler->pdata))->hid_suspend_flag == 1)
{
__disable_irq();
if(OTG_PCGCCTL(otg_core_struct.usb_reg)->pcgcctl_bit.suspendm == 1
&& usb_suspend_status_get(otg_core_struct.usb_reg) == 1)
{
at32_led_off(LED2);
at32_led_off(LED3);
at32_led_off(LED4);
#ifdef USB_OTG_HS
otg_core_struct.usb_reg->gccfg_bit.wait_clk_rcv = TRUE;
#endif
/* congfig the voltage regulator mode */
pwc_voltage_regulate_set(PWC_REGULATOR_ON);
/* enter deep sleep mode */
pwc_deep_sleep_mode_enter(PWC_DEEP_SLEEP_ENTER_WFI);
/* wait clock stable */
delay_us(120);
system_clock_recover();
#ifdef USB_OTG_HS
otg_core_struct.usb_reg->gccfg_bit.wait_clk_rcv = FALSE;
delay_ms(2);
usb_open_phy_clk(otg_core_struct.usb_reg);
#endif
}
((keyboard_type *)(otg_core_struct.dev.class_handler->pdata))->hid_suspend_flag = 0;
__enable_irq();
at32_led_on(LED2);
at32_led_on(LED3);
at32_led_on(LED4);
}
#endif
}
}
三、实验结果 视频地址https://www.bilibili.com/video/BV1ZJ4m1N7of/
串口打印 IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ff629d
IR_DATA=0x00ffe01f
IR_DATA=0x00ffa857
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ffe21d
IR_DATA=0x00ff22dd
IR_DATA=0x00ff02fd
IR_DATA=0x00ff906f
IR_DATA=0x00ff906f
IR_DATA=0x00ff629d
IR_DATA=0x00ff629d
|