IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【无标题】 -> 正文阅读

[嵌入式]【无标题】

使用器材

控制类

STM32F103c8t6最小系统板
在这里插入图片描述

驱动类

L289n电机驱动模块 刷电机
在这里插入图片描述
刷电机

图像捕获类

OV760摄像头
在这里插入图片描述

程序思路

传递周围道路信息
传递当前小车的速度和方向等信息
计算相关值并将数据返还给主控函数
传递信息的主要通道
向主控函数提供电压值,方便控制小车速度
控制电机的转速
控制小车运动方向
主程序
启动
初始化
定时器
红外管
pid算法模块
串口初始化
电机驱动
舵机驱动
控制函数
摄像头

调试过程

电机驱动模块

void moter_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

    //      GPIO 3?ê??ˉ
	RCC_APB2PeriphClockCmd(MOTER_IN1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  MOTER_IN1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(MOTER_IN1_PORT, &GPIO_InitStructure);

	
	RCC_APB2PeriphClockCmd(MOTER_IN2_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  MOTER_IN2_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(MOTER_IN2_PORT, &GPIO_InitStructure);
	
	RCC_APB2PeriphClockCmd(MOTER_IN3_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  MOTER_IN3_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(MOTER_IN3_PORT, &GPIO_InitStructure);
	
	RCC_APB2PeriphClockCmd(MOTER_IN4_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  MOTER_IN4_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(MOTER_IN4_PORT, &GPIO_InitStructure);
}

在本段代码的调试过程中,我队遇到了些问题,小车始终有一个轮子不能正常转动,后来发现是下面的代码在编写过程中写错了引脚,而且写错了GPIO的工作模式

 GPIO_InitStructure.GPIO_Pin =  MOTER_IN4_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

摄像头模块

在对摄像头模块的调试过程中,我队发现摄像头根本没有向控制函数传输数据,因为在使用野火串口调试助手时无论如何都无法看到数据
摄像头部分代码如下:

#include "stm32f10x.h"
#include "bsp_usart.h"
#include "ov7670.h"
#include "sccb.h"
#include "bsp_SysTick.h
u16 Row[320];        //用于存储一行像素信息
u16 Color[240][320];   //用于存储一张图片240*320像素的信息
	
int main(void)
{	
    u16 i;
	u16 t=0;
	u16 pixcnt=0;				//像素统计
	u16 linecnt=0;				//行数统计
	systick_init(72);
  初始化USART 配置模式为 115200 8-N-1,中断接收
    USART_Config();
	Usart_SendString( DEBUG_USARTx,"这是一个串口中断接收回显实验\n");
	printf("欢迎使用野火STM32开发板\n\n\n\n");
	
	if(OV7670_Init())
		printf("初始化失败");
	delay_ms(1500);	 	   	
	OV7670_Window_Set(10,174,240,320);	//设置窗口
	delay_ms(1500);
	while(OV7670_VSYNC==0);
		while(OV7670_VSYNC==1)		只有在VSYNC为低时,才传输数据	 
		for(linecnt=0;linecnt<240;linecnt++)		
		{
			while(OV7670_HREF==0);
			for(pixcnt=0;pixcnt<320;pixcnt++)
			{
				while(OV7670_PCLK==0);
				Row[pixcnt]=((GPIOB->IDR&0XF000))>>8;
				while(OV7670_PCLK==1); 
				//Row[pixcnt]<<=8;
				while(OV7670_PCLK==0);  
				Row[pixcnt]|=(GPIOB->IDR&0XF000)>>8; 
				while(OV7670_PCLK==1);	
				Row[pixcnt]=((Row[pixcnt]&0xF800)>>11) + ((Row[pixcnt]&0x07E0)>>5) + (Row[pixcnt]&0x001F);
				if(Row[pixcnt]>0x7E) Row[pixcnt]= 0xffff ;//白色             
										else
									{					   Row[pixcnt]=0x00 ;//黑色
										t++;
			}
			 t++;  						
		}
			for(i=0;i<320;i++)
		printf("%d  ",Row[i]);
	}
	printf("黑色像素点的个数:%d",t);
  while(1)
	{	
		while(OV7670_VSYNC==0);
		while(OV7670_VSYNC==1)	
			for(linecnt=0;linecnt<240;linecnt++)		
		{
			while(OV7670_HREF==0);
			for(pixcnt=0;pixcnt<320;pixcnt++)
			{
			while(OV7670_PCLK==0);
				Row[pixcnt]=(((GPIOC->IDR&0X0F00)+(GPIOB->IDR&0XF000))>>8);
				while(OV7670_PCLK==1);
				while(OV7670_PCLK==0);  
				while(OV7670_PCLK==1);	
				Row[pixcnt]=((Row[pixcnt]&0xF800)>>11) + ((Row[pixcnt]&0x07E0)>>5) + (Row[pixcnt]&0x001F);
				if(Row[pixcnt]>0x7E) Row[pixcnt]= 0xffff ;            
										else
									{					   Row[pixcnt]=0x00 ;
			}
			   						
		}
			for(i=0;i<320;i++)
		printf("%d  ",Row[i]);
	}	
}
}
/**************************************

经过我队不断调试和在网上收集相关资料,最后将问题锁定在摄像头的时钟频率上,我队用最小系统板的PA8引脚向摄像头提供频率,但是由于系统板二分频的原因,导致分给摄像头的频率不够,最后我队决定将系统板超频到96M,经过二分频后时48M,此时摄像头正常工作。

舵机模块

部分代码如下:

static void GENERAL_TIM_Mode_Config(void)
{
  
	GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period-1;	
	TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler-1;	
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	TIM_OCStructInit(& TIM_OCInitStructure);      
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	
	
	TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	
	TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	
	TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	
	TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM4, ENABLE);
	TIM_CtrlPWMOutputs(TIM4,ENABLE);	
	
	TIM_Cmd(GENERAL_TIM, ENABLE);

}

void GENERAL_TIM_Init(void)
{
	GENERAL_TIM_GPIO_Config();
	GENERAL_TIM_Mode_Config();		
}

控制函数中舵机模块的代码

turn_left();
Delay_ms(2000);
left_back();
Delay_ms(2000);
turn_right();
Delay_ms(2000);
right_back();
Delay_ms(2000);
receiving_process();//等待PID处理

在本模块中,我队原来是直接调用turn_left和turn_right函数进行转向,但是发现转动角度及其微小。
后来,通过添加延时函数,让舵机运行的时间延长一会,成功获得了较大角度的转向。

PID调速图像

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

部分模块关键代码

定时器模块

static void GENERAL_TIM_Mode_Config(void)
{
  
	GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);


  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	
	TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period-1;	
	
	TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler-1;	
	
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;		
	
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	

	TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);


	
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	TIM_OCStructInit(& TIM_OCInitStructure);      
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	
	
	TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	

	TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	
	TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	
	TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);
	TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM4, ENABLE);
	TIM_CtrlPWMOutputs(TIM4,ENABLE);	
	
	TIM_Cmd(GENERAL_TIM, ENABLE);
}

void GENERAL_TIM_Init(void)
{
	GENERAL_TIM_GPIO_Config();
	GENERAL_TIM_Mode_Config();		
}

高级定时器模块

static void ADVANCE_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		
		
    NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ ;	
	
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
	
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
static void ADVANCE_TIM_Mode_Config(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;		
		
    ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK, ENABLE);	
		
    TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_Period;
	
    TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_Prescaler;	
		
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
		
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 		
		
		TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	 
    TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
	
	
    TIM_ClearFlag(ADVANCE_TIM, TIM_FLAG_Update);
	  
		
    TIM_ITConfig(ADVANCE_TIM,TIM_IT_Update,ENABLE);
		
		
    TIM_Cmd(ADVANCE_TIM, ENABLE);
}

void ADVANCE_TIM_Init(void)
{
	ADVANCE_TIM_NVIC_Config();
	ADVANCE_TIM_Mode_Config();		
}

红外管模块

#include "honwai.h"



u8 L2_Val, L1_Val, M_Val, R1_Val, R2_Val;
int Line_Num;

void honwai_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd( LEFTHONWAI_GPIO_CLK|RIGHTHONWAI_GPIO_CLK, ENABLE);
	
	
		GPIO_InitStructure.GPIO_Pin = LEFTONE_GPIO_PIN|LEFTMOST_GPIO_PIN;	

		
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   
	
		GPIO_Init(LEFTHONWAI_GPIO_PORT, &GPIO_InitStructure);	
	
	GPIO_InitStructure.GPIO_Pin =RIGHTMOST_GPIO_PIN|RIGHTONE_GPIO_PIN;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(RIGHTHONWAI_GPIO_PORT, &GPIO_InitStructure);	
	
}


void Light_GoStraight_control(void)  
{
	  get_line_ttl();  
	

	  if(L1_Val == 0 &&  M_Val == 1 && R1_Val == 0 )  Line_Num =  0;
	  if(L1_Val == 0 &&  M_Val == 1 && R1_Val == 1) Line_Num =  550;
	  if(L1_Val == 0 &&  M_Val == 0 && R1_Val == 1 )  Line_Num =600;
	  if(L1_Val == 1 &&  M_Val == 0 && R1_Val == 0) Line_Num = -600;   
    if(L1_Val == 1 &&  M_Val == 1 && R1_Val == 0) Line_Num = -550;	

}



void get_line_ttl(void)  
{
	if(left_most==SET){L2_Val = 1;} else {L2_Val = 0;}
	if(left_one == SET){L1_Val = 1;} else {L1_Val = 0;}

	if(right_one == SET){R1_Val = 1;} else {R1_Val = 0;}
	if(right_most == SET){R2_Val = 1;} else {R2_Val = 0;}
	
}
/*  */

PID算法模块

#include "./pid/bsp_pid.h"



_pid leftpid_location;
_pid leftpid_speed;
_pid rightpid_location;
_pid rightpid_speed;

void leftPID_param_init(void)
{
	
    leftpid_location.target_val=0.0;				
    leftpid_location.actual_val=0.0;
    leftpid_location.err=0.0;
    leftpid_location.err_last=0.0;
    leftpid_location.integral=0.0;
  
		leftpid_location.Kp = 0.05;
		leftpid_location.Ki = 0.001	;
		leftpid_location.Kd = 0;

  
    leftpid_speed.target_val=0.0;				
    leftpid_speed.actual_val=0.0;
    leftpid_speed.err=0.0;
    leftpid_speed.err_last=0.0;
    leftpid_speed.integral=0.0;
  
		leftpid_speed.Kp = 5.0;
		leftpid_speed.Ki = 0.7;
		leftpid_speed.Kd = 1.5;
} 
void rightPID_param_init(void)
{
		
    rightpid_location.target_val=0.0;				
    rightpid_location.actual_val=0.0;
    rightpid_location.err=0.0;
    rightpid_location.err_last=0.0;
    rightpid_location.integral=0.0;
  
		rightpid_location.Kp = 0.05;
		rightpid_location.Ki = 0.001;
		rightpid_location.Kd = 0;

   
    rightpid_speed.target_val=0.0;				
    rightpid_speed.actual_val=0.0;
    rightpid_speed.err=0.0;
    rightpid_speed.err_last=0.0;
    rightpid_speed.integral=0.0;
  
		rightpid_speed.Kp = 5.0;
		rightpid_speed.Ki = 0.7;
		rightpid_speed.Kd = 1.5;
}


void set_pid_target(_pid *pid, float temp_val)
{
  pid->target_val = temp_val;    
}


float get_pid_target(_pid *pid)
{
  return pid->target_val;  
}


void set_p_i_d(_pid *pid, float p, float i, float d)
{
  	pid->Kp = p;   
		pid->Ki = i;    
		pid->Kd = d;    
}


float location_pid_realize(_pid *pid, float actual_val)
{
		
    pid->err = pid->target_val - actual_val;
  
    
    if((pid->err >= -40) && (pid->err <= 40))
    {
        pid->err = 0;
        pid->integral = 0;
    }
    
  
    if (pid->err > -1500 && pid->err < 1500)
    {
        pid->integral += pid->err;   
        
        
        if (pid->integral > 4000) 
            pid->integral = 4000;
        else if (pid->integral < -4000) 
            pid->integral = -4000;
    }

		
    pid->actual_val = pid->Kp * pid->err + 
                      pid->Ki * pid->integral + 
                      pid->Kd * (pid->err - pid->err_last);
  
		
    pid->err_last = pid->err;
    
	
    return pid->actual_val;
}


float speed_pid_realize(_pid *pid, float actual_val)
{
		
    pid->err = pid->target_val - actual_val;

    if((pid->err<0.2f ) && (pid->err>-0.2f))
        pid->err = 0.0f;

    pid->integral += pid->err;   

		
    pid->actual_val = pid->Kp * pid->err + 
                      pid->Ki * pid->integral + 
                      pid->Kd * (pid->err - pid->err_last);
  
		
    pid->err_last = pid->err;
    
		
    return pid->actual_val;
}


float curr_pid_realize(_pid *pid, float actual_val)
{
		
    pid->err=pid->target_val-actual_val;

    pid->integral += pid->err;   
  

  
  
    if (pid->integral > 2000) 
        pid->integral = 2000;
    else if (pid->integral < -2000) 
        pid->integral = -2000;

		
    pid->actual_val = pid->Kp * pid->err + 
                      pid->Ki * pid->integral + 
                      pid->Kd * (pid->err - pid->err_last);
  
		
    pid->err_last=pid->err;
    
		
    return pid->actual_val;
}


/* */

校赛总结

在本次校赛过程中,由于是线下比赛,队内沟通是个相当大的挑战,我队决定全天开启腾讯会议,线上交流,并且分模块,分功能,分阶段将整个工程细化分派给三名成员,由三名成员将各自的代码完成过后,交给队长统一协调,并完成最后的主控部分。在紧张的赛程中,遇到了很多艰难的挑战,队员难免出现退缩,畏惧的情绪,队员之间的不协调,出现矛盾也是正常的情况,好在不断调整,最后众志成城,其利断金,最后圆满完成了校赛的赛程,在这个过程中,我队成员不仅学习到了许多新的知识,更深厚了同学情谊,为日后应对其他挑战打下了坚实的基础。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:42:18  更:2022-07-21 21:43:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:42:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码