USART通信stm32与openmv控制舵机
1内容简介:
openmv端执行模板匹配功能,将匹配到的模板图片编号发送给stm32端,串口接收到数据相应调用舵机旋转角度。
2.接线
openmv ------- stm32
p4(Tx) - gpiob11(RX)
p5(RX) - gpiob10(TX)
ground - ground
STM32 -------- TTL
Tx - gpiob11(RX)
RX - gpiob10(TX)
ground - ground
舵机 ------- STM32
vcc(红线)- vcc
ground - ground
信号线 - gpioa1

3.openmv端代码
import sensor
import image
from image import SEARCH_EX
from pyb import UART
# 初始化摄像头
sensor.reset()
sensor.set_contrast(1)
sensor.set_gainceiling(16)
sensor.set_framesize(sensor.QQVGA)
sensor.set_pixformat(sensor.GRAYSCALE)
# 初始化串口
uart = UART(3, 115200)
# 加载模板
templates = []
template_to_id = {"1.pgm": 1, "3.pgm": 3, "8.pgm": 8}
for t in ["1.pgm", "3.pgm", "8.pgm"]:
try:
template = image.Image(t)
templates.append(template)
except Exception as e:
print(f"Failed to load template {t}: {e}")
clock = time.clock()
while True:
best_match = -1
clock.tick()
img = sensor.snapshot()
# 遍历模板匹配
for i, template in enumerate(templates):
r = img.find_template(template, 0.70, step=4, search=SEARCH_EX)
if r:
img.draw_rectangle(r)
template_name = list(template_to_id.keys())[i]
print(template_name) # 打印模板名字
best_match = template_to_id.get(template_name, -1)
# 发送匹配结果
uart.write(f"{best_match if best_match != -1 else 0}\n")
4.stm32端代码
一.主函数:
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Servo.h"
#include "LED.h"
void process_num(int num);
uint8_t RxData; //定义用于接收串口数据的变量
int main(void)
{
LED_Init(); //LED初始化
Serial_Init(); //串口初始化
Servo_Init();
while (1)
{
if (Serial_GetRxFlag() == 1) //检查串口接收数据的标志位
{
RxData = Serial_GetRxData(); //获取串口接收的数据
process_num(RxData);
// LED2_ON();
// Delay_ms(500);
// LED2_OFF();
}
}
}
void process_num(int num)
{
switch(num)
{
case 1:
Servo_SetAngle(90); // 接收到 1 时,舵机转动到 90 度
break;
case 3:
Servo_SetAngle(0); // 接收到 3 时,舵机转动到 0 度
break;
case 8:
Servo_SetAngle(180); // 接收到 8 时,舵机转动到 180 度
break;
default:
// 其他情况不动作
break;
}
}
二.Serial端usart通信:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <Servo.h>
#include <Serial.h>
// USART3 的 TX 为 GPIOB10, RX 为 GPIOB11
uint8_t Serial_RxData; //定义串口接收的数据变量
uint8_t Serial_RxFlag; //定义串口接收的标志位变量
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); // 将 PB10 引脚初始化为复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); // 将 PB11 引脚初始化为上拉输入
// 配置 USART
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 开启串口接收数据的中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// NVIC 配置
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART3, ENABLE); // 使能串口,串口开始运行
}
uint8_t Serial_GetRxFlag(void)
{
if (Serial_RxFlag == 1) //如果标志位为1
{
Serial_RxFlag = 0;
return 1; //则返回1,并自动清零标志位
}
return 0; //如果标志位为0,则返回0
}
uint8_t Serial_GetRxData(void)
{
return Serial_RxData; //返回接收的数据变量
}
void USART3_IRQHandler(void)
{
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET) //判断是否是USART3的接收事件触发的中断
{
Serial_RxData = USART_ReceiveData(USART3); //读取数据寄存器,存放在接收的数据变量
Serial_RxFlag = 1; //置接收标志位变量为1
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除USART1的RXNE标志位
}
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART3, Byte);
while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}
三.舵机运动代码:
#include "PWM.h"
void Servo_Init(void)
{
PWM_Init();
}
void Servo_SetAngle(float Angle)
{
PWM_SetCompare2(Angle / 180 * 2000 + 500);
}```
pwm端:
```#include "stm32f10x.h" // Device header
//ÅäÖÃTIM2µÄCH2ͨµÀ GPIOAµÄ1Òý½Å
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2, Compare); //ÉèÖÃCCR
}

浙公网安备 33010602011771号