基于飞思卡尔XS128单片机 摄像头采集测试程序
OV7620采集程序说明:摄像头数据口接PA0-PA7;行中断接PT0,场中断接PT1;
S0为单片机RXD,接到串口模块的TXD中,S1为单片机TXD,接到单片机RXD中
波特率默认为9600,用户可自行修改波特率,图像大小为64*50,帧头帧尾都为0x01
#include <hidef.h>
#include "derivative.h"
#define uint unsigned int
#define uchar unsigned char
#define RowMax 50 //图像行数
#define ColumnMax 64 //图像列数
uchar hang_count;
uint hang,lie;
unsigned char ImageData[RowMax][ColumnMax]; //图像数据数组
void Delay(uint tt)
{
uint i;
for(i=0;i
}
void crg_init(void) //时钟初始化函数
{
CLKSEL=0X00; //时钟选择寄存器
PLLCTL_PLLON=1; //锁相环电路允许
SYNR=0XC0|0X07; //时钟合成寄存器
REFDV=0X80|0X01; //pllclok=2osc(1+SYNR)(1+REFDV)=128M
POSTDIV=0X00;
_asm(nop);
_asm(nop);
while(!(CRGFLG_LOCK==1)); //等待锁相环稳定
CLKSEL_PLLSEL=1; //应用锁相环
}
void IO_init(void)
{ // IO初始化函数
DDRA = 0X00;
}
void ect_init()
{
TIOS=0x00; //T0、T1设置为输入捕捉,摄像头行场中断---关输出比较通道7
TCTL4=0x09; //通道0为上升沿捕捉,1为下降沿捕捉
TIE=0x03; //开场中断,行中断
TSCR1=0x80; //定时器正常工作
TSCR2=0x00; //最后三位为预分频因子选择位
TFLG1=0xFF; //清除该位
TFLG2=0x80; //清除 TOF
}
void Init_SCI(void)
{
SCI0CR1 = 0x00; // 8位数据位,无奇偶校验
SCI0CR2 = 0x2c; //允许接收和发送数据,允许接收中断功能
SCI0BD = 0x22; // 115200波特率
}
void SCI_Send_Byte(unsigned char data)
{
while (!SCI0SR1_TDRE); // 等待发送数据寄存器中的值->发送移位寄存器中
while (!SCI0SR1_TC); // 等待发送移位寄存器中的数值发送完成
SCI0DRL = data;
}
void SCI_Send_Image_String(unsigned char *putchar, uint num)
{
uint i = 0;
for(i=0;i
{
if(putchar[i]==0x01)putchar[i]=0x02;
SCI_Send_Byte(putchar[i]);
}
}
void main(void)
{
crg_init();
ect_init();
IO_init() ;
Init_SCI();
EnableInterrupts;
for(;;)
{
}
}
#pragma CODE_SEG NON_BANKED
void interrupt 8 Port0_Interrupt()
{
int i=0;
TFLG1=0x01; //清行中断标志位
if(hang%4==0) //隔4行采集一次
{
Delay(35);
for(lie=0;lie
{
ImageData[hang_count][lie]=PORTA; //隔一小段时间采集一列数据
asm("nop");
asm("nop");
}
hang_count++;
}
hang++; //行计数器加 1
if(hang_count==RowMax)
{
TIE=0x02; //关行中断
DisableInterrupts;
SCI_Send_Byte(0x01);
SCI_Send_Image_String(&ImageData[0][0],RowMax*ColumnMax); //发送图像数组
SCI_Send_Byte(0x01);
TIE=0x02; //开场中断
EnableInterrupts;
}
}
#pragma CODE_SEG NON_BANKED
interrupt 9 void PT1_Interrupt(void)
{
TFLG1=0x03; //清场中断,行中断
TIE=0x03; //开行中断
hang=0; //行列计数清空
lie=0;
hang_count=0;
}
智能车上位机全功能版
-------摄像头组协议说明文档
一、发送图像的协议:
要想上位机能够正确显示下位机发送过来的灰度图像数据就必须注意以下几点:
A. 首先要确保上下位机设置的波特率要一致。否则接收到的数据全部是乱的,此时上位机的状态是:接收到字节数,但显示全部丢失。
B. 设置好上位机的图像大小,要保证跟下位机发送的图像大小一致。
图像宽度,即图像数组的总列数,图像高度,即图像数组的总行数。
如果上位机的图像大小跟下位机发送的不一致,那么此时上位机的状态将是:
C. 发送图像数据之前请先发送一个帧头0x01到串口。
D. 发送图像数据的过程中,请你多加一个判断语句,如果当前要发送的图像数据跟帧头0x01一样,请你该发另一个数比如0x02。(我们最好要这么样做,因为帧头是告诉上位机一帧图像的接收开始,当上位机接收到0x01时就要从0开始计数,当计数到一幅图像的大小后,如果再接收到一个0x01,就表明这幅图像完整接收了,中途中没有数据的丢失,这时候上位机才把这幅正确的图像显示出来。否则,当上位机的计数尚未等于一幅图像的全部字节数又接收到一个0x01,就认为这幅图像是已经在传输中有丢失了。此时上位机的处理是直接丢弃这幅不完整的图像,也许你可能要说干嘛要全部丢掉呢,把接收不足的字节数用0或者1任意一个字节来填充不就好了吗。想法固然是好的,但是这是不可行的,因为我们不知道这幅图像数据到底丢失哪一部分,我们无法对这部分进行填充处理,假如我们填充的地方错误,那么图像将混乱不清,这时候对你的调试将带来无限的麻烦,不知道到底哪里出了问题的。)
E. 在一幅图像数据全部发送完的后面再发一个0x01到串口,因为上位机接收的一幅图像的判断是前一个0x01后一个0x01中间长度恰好是一幅图像大小。如果在一幅图像数据全部发送完的后面不发送0x01时,如果是连续发送过程,那么你将丢失最后的一幅图像,如果你只发一幅图像,那么上位机将显示不出任何图像。
发送灰度图像经典样例:
比如说你采集的图像尺寸为80*30,ImageData[HEIGHT][WIDTH]为二维数组存放图像,SendByte(c)为发送c到串口的函数
首先我们先打开上位机,设置好上位机的图像大小为80*30.
然后下位机的发送代码如下:
#define WIDTH 80 //图像宽度,即数组列数
#define HEIGHT 30 //图像高度,即数组行数
unsigned char ImageData[HEIGHT][WIDTH];
/发送一帧图像的函数里面要写的代码开始
//先发送帧头,发送0x01到串口
SendByte(0x01);
//发送图像数据
for(i=0;i
{
for(j=0;j
{
//如果图像数据中跟帧头一样的数据,则改之。
// 避免图像数据与帧头冲突,导致上位机误判断为图像边界而
//引起的数据大量丢失的情况。
if(ImageData[j] == 0x01) {ImageData[j]=0x02;}
SendByte(ImageData[j]);
}
}
// 最好在一帧图像数据发完后也要发一个帧头标志.
//避免只发一帧图像的时候上位机检测不到下一个帧头而显示不出图像//的尴尬局面。
SendByte(0x01);//发送0x01到串口
///发送一帧图像的函数里面要写的代码结束//
二、只发图像中心线的协议:
A、问题描述:
我们发送的完整一幅图像数据的时候,由于数据量大,只能在前期调试和研究图像处理的时候有用处,但是当我们到后期调试的时候,我们就没有必要发送完整的一幅图像数据了。我们只想看看我们对图像进行的中心线提取到底稳定情况如何。所以我们只要发送提取到的中心线数据就行了。因为中心线数据很少,所以可以让车边跑边发送中心线回来。
B、操作第一步:把上位机界面上的只接收中心线选项打勾。
C、设置好上位机的图像大小跟下位机的图像大小一致。(说明:
因为上位机接收到一条完整的中心线后需要还原出这条中心线在这幅图像的位置。如果没有设置,那么上位机还原出来的中心线位置就不是原图实际的中心线位置了。)
C、下位机发送的数据格式如下:
首先先发两个字节0XFF 0XFF的帧头数据
然后再发送中心线数组:假如你的图像数组大小为:100列,50行。
那么你提取到的中心线将是一个50个字节大小的数组。
你只要再发送这50个大小的中心线数组数据就可以了。
此时整个发送数据有:0XFF 0XFF + 一个中心线数组。
发表评论 取消回复