使用RA6M4开发板的I2C用于控制PWM输出模块,串口与蓝牙模块hc-05通信,满足短距离机器人与手机间的通信。
本项目实现了使用手机通过蓝牙控制双足机器人前进、左转、右转等功能。
手机发送蓝牙信号命令至控制板,控制板通过HC05模块进行接收,并处理。通过I2C控制PWM模块,进而分别控制6个舵机。PCA9685模块是使用I2C总线可以控制16路舵机模块,在后续舵机控制中也会更方便。舵机采用的是MG995,金属齿轮,满足。
新增串口1
首先打开RA工具,在PIn Selection选择区中选择connectivity:SCI
选中SCI1,设置模式为Asynchronous UART模式
点击Stacks栏,点击New Stack,如下图选择串口。
点击串口,编辑串口名 通道设定波特率等信息,见下图,由于hc-05的默认波特率是9600,这时我们就设置9600.
点击Generate Project Content。关闭RA软件
点击RT-Thread Setting,打开串口1
在hal_entry.c文件中新增串口接收函数,并在hal_entry函数中调用HC05_UART_Entry();即可
#define HC05_UART_NAME "uart1"
/* 串口接收消息结构*/
struct rx_msg
{
rt_device_t dev;
rt_size_t size;
};
/* 串口设备句柄 */
static rt_device_t serial;
/* 消息队列控制块 */
static struct rt_messagequeue rx_mq;
rt_uint8_t hc_cmd;
void HC05_UART_Entry(void);
/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
struct rx_msg msg;
rt_err_t result;
msg.dev = dev;
msg.size = size;
result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
if ( result == -RT_EFULL)
{
rt_kprintf("message queue full!
");
}
return result;
}
static void serial_thread_entry(void *parameter)
{
struct rx_msg msg;
rt_err_t result;
rt_uint32_t rx_length;
static char rx_buffer[200 + 1];
while (1)
{
rt_memset(&msg, 0, sizeof(msg));
/* 从消息队列中读取消息*/
result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
if (result == RT_EOK)
{
/* 从串口读取数据*/
rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
rx_buffer[rx_length] = '';
hc_cmd=rx_buffer[0] ;
}
}
}
void HC05_UART_Entry(void)
{
static char msg_pool[256];
char str[] = "hello RT-Thread!666
";
serial = rt_device_find(HC05_UART_NAME);
if (!serial)
{
rt_kprintf("find %s failed!
", HC05_UART_NAME);
}
rt_mq_init(&rx_mq, "rx_mq",
msg_pool,
sizeof(struct rx_msg),
sizeof(msg_pool),
RT_IPC_FLAG_FIFO);
rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX);
rt_device_set_rx_indicate(serial, uart_input);
rt_device_write(serial, 0, str, (sizeof(str) - 1));
rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
rt_kprintf("Create %s Entry failed!
", HC05_UART_NAME);
}
}
添加PWM模块
在软件包中搜寻PCA9685组件并添加。打开I2C.
设置引脚,注意这是16进制。
舵机控制
static void Servo_entry(void *parameter)
{
run_state=0;
left_up_num=left_up_int_num;
left_mid_num=left_mid_int_num;
left_down_num=left_down_int_num;
right_up_num=right_up_int_num;
right_mid_num=right_mid_int_num;
right_down_num=right_down_int_num;
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_kprintf("Servo_entry
");
while (1)
{
if(hc_cmd!=0)
{
run_state=hc_cmd;
hc_cmd=0;
rt_kprintf("run_state=%d
",run_state);
switch (run_state) {
case 0x00:{
rt_thread_mdelay(1);
break;}
case 0x31:{
go_left_step(50,2,100);
go_right_step(50,2,100);
break;}
case 0x32:{
go_left(50,2,100);
break;}
case 0x33:{
go_right(50,2,100);
break;}
default:
rt_thread_mdelay(1);
break;
}
}
rt_thread_mdelay(20);
}
}
和PWM初始化等其他的程序详见我的附件。
遇到的一点麻烦
在实际测试的时候发现PCA9685模块I2C通信正常,但是就是不能输出PWM,然后就进行一行一行的排查在pca9685.c的代码中pca9685_set_pwm_freq函数中
if (PWM_All_Call)
{
oldmode |= 0xA1;
}
else
{
oldmode |= 0xA0;
}
LOG_D("auto run..
");
write_reg(dev, PCA9685_MODE1, 1, &oldmode);
oldmode按道理来说 oldmode的最高位进行置1进行了复位;
最后在write_reg前新增了一句oldmode |= 0x80;模块正常运行。
原作者:403463275