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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32版CCD线性摄像头寻线寻迹小车 -> 正文阅读

[嵌入式]STM32版CCD线性摄像头寻线寻迹小车

基于STM32F103C8T6的CCD线性摄像头寻线寻迹小车


前言

目前大多数的小车寻线寻迹都是用红外对管寻线,这是比较简单也比较成熟的技术方案,且成本也低。本文将介绍使用CCD线性摄像头寻线寻迹。


一、模块介绍

TSL1401 线性传感器由一个 1x128 的光电二极管阵列、相关的电荷放大电路以及一个内部像素数据保功能组成。内部像素数据保功能可以为所有像素点提供同时积分的开始和停止时间。该阵列由 128 个像素组成,每个像素的感光面积为 3,524.3 平方微米。 像素之间的间隔为 8μm。内部控制逻辑简化了操作,该模块需要串行输入(SI)信号和时钟信号(CLK)。

在这里插入图片描述

二、使用说明

1.引脚说明

在这里插入图片描述
通过查看数据手册模块的管脚介绍如上

  1. AO: 信号输出(供单片机进行信号采集读取)
  2. CLK: 时钟信号
  3. GND: 地线
  4. SI: 信号输入(单片机向 CCD 发送指令)
  5. VDD: 电源(模块引脚标识为 VCC,接单片机逻辑电平,支持 3~5V)

2.其他

CCD 传感器是光学传感器,会受到环境光线的影响;程序中已经运用了动态阈值算法,尽量减小环境光线的影响,但是太暗或者太亮的环境下是不能正常工作的(一般室内正常光线可以运行)。

三、模块调试

在CCD调试助手中可以看出,当CCD摄像头扫描到黑线时,会出现一个凹槽,左右移动,凹槽也移动,脱离黑线凹槽消失。从这条线大概可以看出中值为多少。
在这里插入图片描述
通过串口助手打印出的中值结果如下:
在这里插入图片描述

四、部分代码

1.CCD摄像头相关代码

首先对CCD摄像头初始化所用到的管脚初始化:

void Ccd_Init(void)
{ 
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PA端口时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;				 //PA.2 端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOA.2
	GPIO_SetBits(GPIOA,GPIO_Pin_2);						 //PA.2 输出高

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;	    		 //PA.3 端口配置, 推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
	GPIO_SetBits(GPIOA,GPIO_Pin_3); 						 //PA.7	输出高
}

获取中值:

void RD_TSL(void) 
{
	u8 i=0,tslp=0;
		
	static u8 j,Left,Right,Last_CCD_Zhongzhi;
	static u16 value1_max,value1_min;
		
	TSL_CLK=1;     //CLK引脚设为高电平          
	TSL_SI=0; 
	Dly_us(TIME_us);
				
	TSL_SI=1; 
	TSL_CLK=0;
	Dly_us(TIME_us);
				
	TSL_CLK=1;
	TSL_SI=0;
	Dly_us(TIME_us); 
	for(i=0;i<128;i++)
	{ 
		TSL_CLK=0; 
		Dly_us(TIME_us);  //调节曝光时间
		ccd_adc[tslp]=(u8)((float)Get_Adc(ADC_Channel_1)/4096*255);  //将读取到的电压值存入数组中
		++tslp;
		TSL_CLK=1;
		Dly_us(TIME_us);
	} 

	value1_max=ccd_adc[0];  //动态阈值算法,读取最大和最小值
	for(i=5;i<123;i++)   //两边各去掉5个点
	{
		if(value1_max<=ccd_adc[i])
		value1_max=ccd_adc[i];
	}
	value1_min=ccd_adc[0];  //最小值
	for(i=5;i<123;i++) 
	{
		if(value1_min>=ccd_adc[i])
		{
			value1_min=ccd_adc[i];				
		}
	 }
	 CCD_Yuzhi=(value1_max+value1_min)/2;	  //计算出本次中线提取的阈值
	 for(i = 5;i<118; i++)   //寻找左边跳变沿
	 {
		if(ccd_adc[i]>CCD_Yuzhi&&ccd_adc[i+1]>CCD_Yuzhi&&ccd_adc[i+2]>CCD_Yuzhi&&ccd_adc[i+3]<CCD_Yuzhi&&ccd_adc[i+4]<CCD_Yuzhi&&ccd_adc[i+5]<CCD_Yuzhi)
		{	
			Left=i;
			break;	
		}
	 }
	 for(j = 118;j>5; j--)//寻找右边跳变沿
	 {
		if(ccd_adc[j]<CCD_Yuzhi&&ccd_adc[j+1]<CCD_Yuzhi&&ccd_adc[j+2]<CCD_Yuzhi&&ccd_adc[j+3]>CCD_Yuzhi&&ccd_adc[j+4]>CCD_Yuzhi&&ccd_adc[j+5]>CCD_Yuzhi)
		{	
			Right=j;
			break;	
		}
	 }
	CCD_Zhongzhi=(Right+Left)/2;//计算中线位置
	if(myabs(CCD_Zhongzhi-Last_CCD_Zhongzhi)>70)   //计算中线的偏差,如果太大
	CCD_Zhongzhi=Last_CCD_Zhongzhi;    //则取上一次的值
	Last_CCD_Zhongzhi=CCD_Zhongzhi;  //保存上一次的偏差	
		
}

发送至上位机调试:

void sendToPc(void)
{ 
	int i;
	slove_data();
	printf("*");
	printf("LD");
	for(i=2;i<134;i++)
	{ 
		printf("%c",binToHex_high(SciBuf[i])); //以字符形式发送高4位对应的16进制
		printf("%c",binToHex_low(SciBuf[i]));  //以字符形式发送低?位对应的16进制
	}
	printf("00");   //通信协议要求
	printf("#");    //通信协议要求
}

2.ADC采集相关代码

ADC定义初始化:

void  Adc_Init(void)
{ 	
	ADC_InitTypeDef ADC_InitStructure; 
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1	, ENABLE );	  //使能ADC1通道时钟
 

	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

	//PA1 作为模拟通道输入引脚                         
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_Init(GPIOA, &GPIO_InitStructure);	

	ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//模数转换工作在单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

  
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1
	
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	 
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
	ADC_StartCalibration(ADC1);	 //开启AD校准
 
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
 
//	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能

}

获取ADC值:

//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
  	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC1,ADC通道,采样时间为239.5周期	  			    
  
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

3.主函数代码

u8 CCD_Zhongzhi=64,CCD_Yuzhi;                 //线性CCD相关

int main(void)
{	 
	int piancha=0,jiaodu;
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart_init(115200);	 //串口初始化为115200 
		
	Adc_Init();	//ADC初始化
	Ccd_Init(); //CCD初始化
	TIME_us=1;  //设置曝光时间
	 
	TIM1_PWM_Init(7199,0);   	//=====初始化PWM 10KHZ,用于驱动电机。 
	Motor_Init();				//=====初始化与电机连接的硬件IO接口
	SERVO_Init();               //=====舵机PWM定时器3, 初始占空比7.5%	 
		
	while(1)
	{  
//		sendToPc();   //发送信息至上位机
		RD_TSL();		//获取中值
		printf("%d\n",CCD_Zhongzhi);
		piancha = (CCD_Zhongzhi-64)/3;
		jiaodu = 75+piancha;
		SERVO_Angle_Control(jiaodu);
		go();
	}
}

四、小车硬件

主控:STM32F103C8T6
摄像头:线性CCD( TSL1401CL)
电机驱动:TB6612FNG
舵机一个
电机两个
LM2596S稳压模块
7.4V航模锂电池

五、演示视频

CCD摄像头寻线寻迹小车


总结

用CCD线性摄像头寻迹寻线小车跑起来更稳更丝滑,跑黑线的类型也多一点。参考:线性CCD基础学习

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:38:02  更:2021-08-21 15:39:26 
 
开发: 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年5日历 -2024/5/21 3:42:45-

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