这段代码是一个用于控制PS2手柄的应用程序,主要功能是通过PS2手柄来控制一个小车的运动。代码分为几个部分,包括初始化、按键处理、电机控制等。下面我将逐句详细解释这段代码。
#include "app_ps2.h"
#ifndef _APP_PS2_H_
#define _APP_PS2_H_
#include "main.h"
//保存ps2指令
typedef struct
{
/******************** 按下指令 *******************/
/* 左边4个按键 */
char pressed_left_up[32];
char pressed_left_right[32];
char pressed_left_down[32];
char pressed_left_left[32];
/* 右边4个按键 */
char pressed_right_up[32];
char pressed_right_right[32];
char pressed_right_down[32];
char pressed_right_left[32];
/* 中间两个按键 */
char pressed_select[32];
char pressed_start[32];
/* 前面左右各两个按键 */
char pressed_left_1[32];
char pressed_left_2[32];
char pressed_right_1[32];
char pressed_right_2[32];
char pressed_key_rocker_left[32];//摇杆按键
char pressed_key_rocker_right[32];
/******************** 释放指令 *******************/
/* 左边4个按键 */
char release_left_up[32];
char release_left_right[32];
char release_left_down[32];
char release_left_left[32];
/* 右边4个按键 */
char release_right_up[32];
char release_right_right[32];
char release_right_down[32];
char release_right_left[32];
/* 中间两个按键 */
char release_select[32];
char release_start[32];
/* 前面左右各两个按键 */
char release_left_1[32];
char release_left_2[32];
char release_right_1[32];
char release_right_2[32];
char release_key_rocker_left[32];//摇杆按键
char release_key_rocker_right[32];
} ps2_cmd_t;
void app_ps2_init(void);
void app_ps2_run(void);
#endif
这里引入了 app_ps2.h 头文件,该文件包含了与PS2手柄相关的函数声明、宏定义和数据结构。
const char *pre_cmd_set_red[PSX_BUTTON_NUM] = {
// 手柄按键功能字符串 红灯模式下使用
"" , // L2
"" , // R2
"" , // L1
"" , // R1
"" , // RU
"" , // RR
"" , // RD
"" , // RL
"" , // SE
"" , // AL
"" , // AR
"" , // ST
"" , // LU
"" , // LR
"" , // LD
"" , // LL
};
这是一个字符串数组,定义了在红灯模式下每个按键对应的命令字符串。每个字符串代表一个按键的功能,例如 L2、R2 等。
const char *pre_cmd_set_grn[PSX_BUTTON_NUM] = {
// 绿灯模式下按键的配置
"" , // L2 左上500
"" , // R2 右上500
"" , // L1 左上1000
"" , // R1 右上1000
"" , // RU 前进1000
"" , // RR 右平移1000
"" , // RD 后退1000
"" , // RL 左平移1000
"" , // SE
"" , // AL
"" , // AR
"" , // ST
"" , // LU 前进500
"" , // LR 右转500
"" , // LD 后退500
"" , // LL 左转500
};
与红灯模式类似,这里定义了绿灯模式下每个按键对应的命令字符串。
void parse_psx_buf(unsigned char *buf, unsigned char mode);
void loop_ps2_car(void);
这里声明了两个函数,parse_psx_buf 用于解析PS2手柄的按键数据,loop_ps2_car 用于处理小车的电机控制。
void app_ps2_init(void)
{
ps2_init(); /* PS2引脚初始化 */
}
app_ps2_init 函数用于初始化PS2手柄的引脚。
void app_ps2_run(void)
{
static unsigned char psx_button_bak[2] = {0};
static u32 systick_ms_bak = 0;
// 每50ms处理1次
if (millis() - systick_ms_bak < 50)
return;
systick_ms_bak = millis();
ps2_write_read(); /* 读取ps2数据 */
loop_ps2_car(); /* 处理小车电机摇杆控制 */
// 对比两次获取的按键值是否相同 ,相同就不处理,不相同则处理
if ((psx_button_bak[0] == psx_buf[3]) && (psx_button_bak[1] == psx_buf[4]))
{
}
else
{
// printf("parse_psx_buf\r\n");
// 处理buf3和buf4两个字节,这两个字节存储这手柄16个按键的状态
parse_psx_buf(psx_buf + 3, psx_buf[1]);
psx_button_bak[0] = psx_buf[3];
psx_button_bak[1] = psx_buf[4];
}
}
app_ps2_run 函数是主循环函数,每50ms执行一次。它首先读取PS2手柄的数据,然后调用 loop_ps2_car 处理小车的电机控制。接着,它比较当前按键状态与上一次的状态,如果不同则调用 parse_psx_buf 处理按键事件。
void loop_ps2_car(void)
{
float car_left1=0, car_right1=0, car_left2=0, car_right2=0;
static float car_left1_bak = 0, car_right1_bak = 0, car_left2_bak = 0, car_right2_bak = 0;
static u8 num = 10;
if (psx_buf[1] != PS2_LED_RED)
return;
if (abs_int(127 - psx_buf[7]) > num)
{
car_left1=car_left1-(0x7f-psx_buf[7])*2;
car_right1=car_right1+(0x7f-psx_buf[7])*2;
car_left2=car_left2-(0x7f-psx_buf[7])*2;
car_right2=car_right2+(0x7f-psx_buf[7])*2;
}
if (abs_int(127 - psx_buf[8]) > num)
{
car_left1=car_left1+(0x7f-psx_buf[8])*2;
car_right1=car_right1+(0x7f-psx_buf[8])*2;
car_left2=car_left2+(0x7f-psx_buf[8])*2;
car_right2=car_right2+(0x7f-psx_buf[8])*2;
}
if (abs_int(127 - psx_buf[5]) > num)
{
car_left1=car_left1-(0x7f-psx_buf[5])*2;
car_right1=car_right1+(0x7f-psx_buf[5])*2;
car_left2=car_left2+(0x7f-psx_buf[5])*2;
car_right2=car_right2-(0x7f-psx_buf[5])*2;
}
if (abs_int(127 - psx_buf[6]) > num)
{
car_left1=car_left1+(0x7f-psx_buf[6])*2;
car_right1=car_right1+(0x7f-psx_buf[6])*2;
car_left2=car_left2+(0x7f-psx_buf[6])*2;
car_right2=car_right2+(0x7f-psx_buf[6])*2;
}
if ((car_left1_bak != car_left1) || (car_right1_bak != car_right1) || (car_left2_bak != car_left2) || (car_right2_bak != car_right2))
{
motor_speed_set(car_left1 / 1000, car_right1 / 1000, car_left2 / 1000, car_right2 / 1000);
}
car_left1_bak = car_left1;
car_right1_bak = car_right1;
car_left2_bak = car_left2;
car_right2_bak = car_right2;
}
loop_ps2_car 函数用于处理小车的电机控制。它根据PS2手柄的摇杆数据计算小车的四个电机的速度,并调用 motor_speed_set 函数设置电机速度。
void parse_psx_buf(unsigned char *buf, unsigned char mode)
{
u8 i, pos = 0;
static u16 bak = 0xffff, temp, temp2;
temp = (buf[0] << 8) + buf[1];
if (bak != temp)
{
temp2 = temp;
temp &= bak;
for (i = 0; i < 16; i++)
{ // 16个按键一次轮询
if ((1 << i) & temp)
{
}
else
{
if ((1 << i) & bak)
{ // press 表示按键按下了
memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
if (mode == PS2_LED_RED)
{
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_red[i], strlen(pre_cmd_set_red[i]));
}
else if (mode == PS2_LED_GRN)
{
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_grn[i], strlen(pre_cmd_set_grn[i]));
}
else
continue;
// zx_uart_send_str(uart_receive_buf);
pos = str_contain_str(uart_receive_buf, "^");
if (pos)
uart_receive_buf[pos - 1] = '\0';
if (str_contain_str(uart_receive_buf, "$"))
{
uart1_close();
uart_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf + 11);
strcpy((char *)uart_receive_buf, (char *)cmd_return);
uart_get_ok = 1;
uart1_open();
uart_mode = 1;
}
else if (str_contain_str(uart_receive_buf, "#"))
{
uart1_close();
uart_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf + 11);
strcpy((char *)uart_receive_buf, (char *)cmd_return);
uart_get_ok = 1;
uart1_open();
uart_mode = 2;
}
bak = 0xffff;
}
else
{ // release 表示按键松开了
memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
if (mode == PS2_LED_RED)
{
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_red[i], strlen(pre_cmd_set_red[i]));
}
else if (mode == PS2_LED_GRN)
{
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_grn[i], strlen(pre_cmd_set_grn[i]));
}
else
continue;
pos = str_contain_str(uart_receive_buf, "^");
if (pos)
{
if (str_contain_str(uart_receive_buf + pos, "$"))
{
// uart1_close();
// uart_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf + pos);
cmd_return[strlen((char *)cmd_return) - 1] = '\0';
strcpy((char *)uart_receive_buf, (char *)cmd_return);
parse_cmd(uart_receive_buf);
// uart_get_ok = 1;
// uart_mode = 1;
}
else if (str_contain_str(uart_receive_buf + pos, "#"))
{
// uart1_close();
// uart_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf + pos);
cmd_return[strlen((char *)cmd_return) - 1] = '\0';
strcpy((char *)uart_receive_buf, (char *)cmd_return);
parse_action(uart_receive_buf);
// uart_get_ok = 1;
// uart_mode = 2;
}
// uart1_send_str(uart_receive_buf);
}
}
}
}
bak = temp2;
}
return;
}
parse_psx_buf 函数用于解析PS2手柄的按键数据。它根据按键的状态(按下或松开)以**及当前模式(红灯或绿灯)来执行相应的操作。**函数内部通过 str_contain_str 函数来解析命令字符串,并根据命令类型调用 parse_cmd 或 parse_action 函数。
这段代码的主要功能是通过PS2手柄来控制一个小车的运动。它通过读取手柄的按键和摇杆数据,并根据不同的模式(红灯或绿灯)来执行相应的操作。代码中使用了大量的字符串处理和状态判断,以实现复杂的控制逻辑。
---