飞思卡尔智能车摄像头代码
第九届飞思卡尔智能车竞赛材料清单V3.0
本材料表一共有9页,每个宝贝后面都附带有链接第九届飞思卡尔智能车竞赛光电组材料表(XS128)序号名称单价(元)数量总计(元)链接1MC9S12XS128最小系统(16位)78.75178.75详情2BDM下载器(集成USB转串口)52.5152.5详情3线性CCD模块1201120详情4偏振片15115详情5线性CCD安装支架48148详情6碳素杆(10mm*8mm*500mm)12112详情7舵机支架40140详情8舵机转向舵盘39.6139.6详情9BTN7971电机驱动(4合1)1261126详情10BTN7971驱动芯片17.29469.16详情11LM2940电源芯片428详情12LM2940元件包0.320.6详情13200线编码器(单相)128.11128.1详情14编码器支架12112详情15编码器齿轮(B车)15.2115.2详情16OLED显示屏34.3134.3详情17第9届飞思卡尔竞赛指定B车模详情总计第九届飞思卡尔智能车竞赛光电组材料表(K60)序号名称单价(元)数量总计(元)链接1MK60DN512ZVLL10最小系统(32位)110.71110.7详情2OSJTAG下载器(集成USB转串口)84184详情3线性CCD模块1201120详情4偏振片15115详情5线性CCD安装支架48148详情6碳素杆(10mm*8mm*500mm)12112详情7舵机支架40140详情8舵机转向舵盘39.6139.6详情9BTN7971电机驱动(4合1)1261126详情10BTN7971驱动芯片17.29469.16详情11LM1117-3.3电源芯片428详情12LM1117-3.3元件包0.320.6详情13LM2940电源芯片428详情14LM2940元件包0.320.6详情15200线编码器(单相)128.11128.1详情16编码器支架12112详情17编码器齿轮(B车)15.2115.2详情18OLED显示屏34.3134.3详情19第9届飞思卡尔竞赛指定B车模详情总计第九届飞思卡尔智能车竞赛光电组材料表(MCF52255)序号名称单价(元)数量总计(元)链接1MCF52255最小系统(32位)110.71110.7详情2BDM下载器84184详情3线性CCD模块1201120详情4偏振片15115详情5线性CCD安装支架48148详情6碳素杆(10mm*8mm*500mm)12112详情7舵机支架40140详情8舵机转向舵盘39.6139.6详情9BTN7971电机驱动(4合1)1261126详情10BTN7971驱动芯片17.29469.16详情11LM1117-3.3电源芯片428详情12LM1117-3.3元件包0.320.6详情13LM2940电源芯片428详情14LM2940元件包0.320.6详情15200线编码器(单相)128.11128.1详情16编码器支架12112详情17编码器齿轮(B车)15.2115.2详情18OLED显示屏34.3134.3详情19第9届飞思卡尔竞赛指定B车模详情总计711.1元第九届飞思卡尔智能车竞赛摄像头组材料表(XS128)序号名称单价(元)数量总计(元)链接1MC9S12XS128最小系统(16位)78.75178.75详情2BDM下载器(集成USB转串口)52.5152.5详情3摄像头模块OV76201201120详情4偏振片15115详情5摄像头安装支架48148详情6碳素杆(10mm*8mm*500mm)12112详情7MMA7361加速度传感器模块(三轴)21121详情8ENC-03MB陀螺仪模块(双轴)75175详情9BTN7971电机驱动(4合1)1261126详情10BTN7971驱动芯片17.29469.16详情11LM2940电源芯片428详情12LM2940元件包0.320.6详情13200线编码器(双相)147.251147.25详情14编码器支架12112详情15编码器齿轮(D车)15.2115.2详情16OLED显示屏34.3134.3详情17第9届飞思卡尔竞赛指定D车模详情18第9届飞思卡尔竞赛指定E车模详情总计765.6元第九届飞思卡尔智能车竞赛摄像头组材料表(K60)序号名称单价(元)数量总计(元)链接1MK60DN512ZVLL10最小系统(32位)110.71110.7详情2OSJTAG下载器(集成USB转串口)84184详情3摄像头模块OV76201201120详情4偏振片15115详情5摄像头安装支架48148详情6碳素杆(10mm*8mm*500mm)12112详情7MMA7361加速度传感器模块(三轴)21121详情8ENC-03MB陀螺仪模块(双轴)75175详情9BTN7971电机驱动(4合1)1261126详情10BTN7971驱动芯片17.29469.16详情11LM1117-3.3电源芯片428详情12LM1117-3.3元件包0.320.6详情13LM2940电源芯片428详情14LM2940元件包0.320.6详情15200线编码器(双相)147.251147.25详情16编码器支架12112详情17编码器齿轮(D车)15.2115.2详情18OLED显示屏34.3134.3详情19第9届飞思卡尔竞赛指定D车模详情20第9届飞思卡尔竞赛指定E车模详情总计829.05元第九届飞思卡尔智能车竞赛摄像头组材料表(MCF52255)序号名称单价(元)数量总计(元)链接1MCF52255最小系统(32位)110.71110.7详情2BDM下载器84184详情3摄像头模块OV76201201120详情4偏振片15115详情5摄像头安装支架48148详情6碳素杆(10mm*8mm*500mm)12112详情7MMA7361加速度传感器模块(三轴)21121详情8ENC-03MB陀螺仪模块(双轴)75175详情9BTN7971电机驱动(4合1)1261126详情10BTN7971驱动芯片17.29469.16详情11LM1117-3.3电源芯片428详情12LM1117-3.3元件包0.320.6详情13LM2940电源芯片428详情14LM2940元件包0.320.6详情15200线编码器(双相)147.251147.25详情16编码器支架12112详情17编码器齿轮(D车)15.2115.2详情18OLED显示屏34.3134.3详情19第9届飞思卡尔竞赛指定D车模详情20第9届飞思卡尔竞赛指定E车模详情总计序号名称单价(元)数量总计(元)链接1MC9S12XS128最小系统(16位)78.75178.75详情2BDM下载器(集成USB转串口)52.5152.5详情310mH工字电感0.82016详情4 6.8nf电容0.2204详情5LM386运算放大器3412详情6NE5532运算放大器 3.5414详情7干簧管 2.525详情80.3mm漆包线(50米长)15115详情9碳素杆(5cm*3cm*1000mm)10.8110.8详情10碳素杆(6cm*4cm*1000mm)12224详情11碳素杆三通件(垂直) 4.829.6详情12碳素杆三通件(倾斜) 4.829.6详情13舵机支架40140详情14舵机转向舵盘39.6139.6详情15BTN7971电机驱动(4合1)1261126详情16LM2940电源芯片428详情17LM2940元件包0.320.6详情18200线编码器(双相)149.582299.16详情19编码器支架12112详情20编码器齿轮(D车)15.2115.2详情21OLED显示屏34.3134.3详情22第9届飞思卡尔竞赛指定C车模详情总计序号名称单价(元)数量总计(元)链接1MK60DN512ZVLL10最小系统(32位)110.71110.7详情2OSJTAG下载器(集成USB转串口)84184详情310mH工字电感0.82016详情4 6.8nf电容0.2204详情5LM386运算放大器3412详情6NE5532运算放大器 3.5414详情7干簧管 2.525详情80.3mm漆包线(50米长)15115详情9碳素杆(5cm*3cm*1000mm)10.8110.8详情10碳素杆(6cm*4cm*1000mm)12224详情11碳素杆三通件(垂直) 4.829.6详情12碳素杆三通件(倾斜) 4.829.6详情13舵机支架40140详情14舵机转向舵盘39.6139.6详情15BTN7971电机驱动(4合1)1261126详情16BTN7971驱动芯片17.29469.16详情17LM1117-3.3电源芯片428详情18LM1117-3.3元件包0.320.6详情19LM2940电源芯片428详情20LM2940元件包0.320.6详情21200线编码器(双相)149.582299.16详情22编码器支架12112详情23编码器齿轮(D车)15.2115.2详情24OLED显示屏34.3134.3详情25第9届飞思卡尔竞赛指定C车模详情总计第九届飞思卡尔智能车竞赛电磁组材料表(MCF52255)序号名称单价(元)数量总计(元)链接1MCF52255最小系统(32位)110.71110.7详情2BDM下载器84184详情310mH工字电感0.82016详情4 6.8nf电容0.2204详情5LM386运算放大器3412详情6NE5532运算放大器 3.5414详情7干簧管 2.525详情80.3mm漆包线(50米长)15115详情9碳素杆(5cm*3cm*1000mm)10.8110.8详情10碳素杆(6cm*4cm*1000mm)12224详情11碳素杆三通件(垂直) 4.829.6详情12碳素杆三通件(倾斜) 4.829.6详情13舵机支架40140详情14舵机转向舵盘39.6139.6详情15BTN7971电机驱动(4合1)1261126详情16BTN7971驱动芯片17.29469.16详情17LM1117-3.3电源芯片428详情18LM1117-3.3元件包0.320.6详情19LM2940电源芯片428详情20LM2940元件包0.320.6详情21200线编码器(双相)149.582299.16详情22编码器支架12112详情23编码器齿轮(C车)15.2115.2详情24OLED显示屏34.3134.3详情25第9届飞思卡尔竞赛指定C车模详情总计。
TSL1401中文资料
线性CCDTSL140CL中文资料本文档由手创科技团队整理翻译,由于时间仓促与水平有限,翻译难免有所纰漏,敬请谅解并指出,谢谢。
本翻译仅为广大智能车友提供交流和参考作用!望各车友在理论中实践,在实践中创新。
各车友如有自己的心得体会,可开源共享。
最后祝愿所有参加第八届飞思卡尔智能车竞赛的同学都能有超越名次、奖金、证书以外的收获!第八届光电组交流群:185480308 181733362手创科技团队线性CCD TSL1401CL●128×1个传感器单元组织●每英寸400点(DPI)传感器间距●高线性度和均匀度●宽动态范围:4000:1(72分贝)●输出参考地●低图像延迟:0.5%典型值●操作为8 MHz。
●单3-V到5-V供应●轨到轨输出摆幅(AO)●没有外部负载电阻●更换TSL1401R-LF●符合RoHS描述TSL1401CL线性传感器阵列由一个128×1的光电二极管阵列,相关的电荷放大器电路和一个内部的像素数据保持功能组成,它提供了同时集成起始和停止时间的所有像素。
该阵列128个像素,其中每一个具有光敏面积3,524.3平方微米。
像素之间的间隔是8微米。
操作简化内部控制逻辑,只需要一个串行输入端(SI)的信号和时钟CLK。
功能框图引脚功能名称 序号 描述AO 3 模拟输出CLK 2 时钟。
时钟控制的电荷转移,像素输出和复位。
GND 6、7 接地(基板)。
所有电压都参考到基板上。
NC 5、8 无内部连接。
SI 1 串行输入。
SI定义数据输出序列的开始。
VDD 4 电源电压。
模拟和数字电路的电源电压。
详细描述该传感器是包含128个光电二极管的线性阵列。
在光电二极管的光能量冲击下产生的光电流,这是由有源积分电路,与该象素相关的集成。
在积分周期期间,采样电容器连接到积分器的输出通过一个模拟切换。
在每个像素中累积的电荷量是和光强度和积分时间成正比的。
积分器的输出和复位控制由一个128位的移位寄存器和复位逻辑控制的。
飞思卡尔智能车摄像头组新手指南(5)--让车跑起来篇
飞思卡尔智能车摄像头组新⼿指南(5)--让车跑起来篇舵机、电机控制策略让车跑起来彭岸辉控制器设置了快速的控制周期,在每个运算周期内,控制器即时地得到智能车车速以及传感器采样来的道路信号,经过控制算法的计算后,控制单元输出相应的前轮控制转⾓以及电机占空⽐的值,其输出值再经过函数映射关系转换为 PWM 脉宽信号传⾄前轮舵机以及驱动电机,从⽽实现⼀个周期的控制。
由于摄像头的信号是具有周期性的,可以直接采⽤摄像头采集⼀幅图像的周期作为控制周期。
舵机控制采⽤ PD 控制,控制跟随性较好,P可以及时对赛道的变化作出反应,当然舵机的 P 项值也是跟随赛道情况变化的,直道和较⼩的弯道时控制较弱,90 度弯道或 270 度⼤弯道控制量较强,D有预测道路类型的作⽤,也就是能使舵机提前打⾓。
电机控制采⽤ PID 控制,可以减⼩动态误差并且跟随性能较好。
当然也可以使⽤其他控制,很多⼈舵机采⽤P控制,电机采⽤PD或PI控制。
对⽐他们的优缺点⾃⼰选择适合⾃⼰⼩车的PID。
这⾥不进⾏深⼊讲解。
前⾯的⼯作完成后懂得基本的图像处理算法就差不多可以使⼩车跑起来了!要使⼩车跑起来其实不难的,很多初学者最希望的就是看⾃⼰的车跑起来,因为当初我也是这样的,很理解师弟师妹们此刻的想法!最基本的图像处理算法就是:图像中间往两边搜索⿊线注意:初学者在初学时不知道偏差是怎样计算的。
这⾥就提⼀下:偏差就是计算出的中线即图中赛道中的⿊线与摄像头所看到的中线即图中赛道中的竖直红线(例如采集到的图像是100列的,那么摄像头看到的中线就是50)做差得到的值就是偏差。
它表⽰车当前位置与期望位置的偏离程度。
再看个图吧:⽤两⾏来说明,其他的⼀样。
第⼀⾏左边坐标(0,1)右边坐标(0,99),得出的中线就是(0,50),那么50所在的那⼀列就是摄像头所看到的中线(就是图中竖直的红线)。
这⾥再提⼀下,很多⼈提出中线后发现上位机上或LCD上没显⽰出中线,其实显⽰出中线很简单的:根据RGB,⼀个像素点的像素值为255时显⽰出来的是⽩⾊,像素值为0时显⽰出来的是⿊⾊。
飞思卡尔智能车光电源代码
1.#include <hidef.h>2.#include <mc9s12dg128.h>3.#pragma LINK_INFO DERIV ATIVE "mc9s12dg128b"4.//=========================public variable=====================5.//-----------------------turning variable------------------6.unsigned char sam_g[15]; //道路检测值7.unsigned int angle_data; //舵机转角8.int car_positn; //赛车当前位置参数9.int pre_positn;10.unsigned int black_sensor_number; //检测到黑线的传感器个数11.int positn_temp[10];12.unsigned int t=0;13.//---------------------speed variable---------------------14.unsigned char dir_flag; //方向标志,为1表示检测到有效路径,可以给驱动力15.unsigned char brake_flag; //刹车标志位判断当前是否需要刹车16.unsigned int car_driver; //驱动力控制17.unsigned int pulse_count; //速度检测统计脉冲个数18.unsigned int ideal_speed; //车的理想速度19.unsigned int times; //丢失黑线的次数20.int speed_error; //理想与实际速度偏差值21.int pre_error; //速度PID 前一次的速度误差值ideal_speed- pulse_count22.int pre_d_error; //速度PID 前一次的速度误差之差d_error-pre_d_error23.int pk; //速度PID值24.//---------------------start_line variable-------------------25.unsigned char start_line_acc; //统计检测起跑线次数26.unsigned char finish_flag; //起跑线标志位,为1表示检测到起跑线3次27.//----------------------dis_play variable--------------------28.unsigned int start_flag,start_count;29.//---------------------table-------------------------30.unsigned charspeed_table11[13]={270,260,250,240,200,180,180,180,170,140,140,100,90}; //15.0s31.unsigned char speed_table21[13]= {25,24,23,20,19,17,17,17,15,12,11,10,9}; //15.0s32.unsigned char speed_table12[13]= {29,28,27,26,25,20,20,20,19,17,15,10,9}; //15.0s33.unsigned char speed_table22[13]= {27,26,25,24,20,18,18,18,17,14,14,10,9}; //15.0s34.unsigned int circle; //控制赛车跑几圈停车35.#define kp 2000//200036.#define ki 5//537.#define kd 10//1038.#define Angle_Center 4344 //舵机中心位置39.#define lose_limit 30000 //丢失黑线后滑翔时间40.void data_init(void);41.void crg_init(void); // 锁相环初始化42.void pwm_init(void); // PWM信号初始化43.void ect_init(void); // ECT初始化44.void sam_position(void); //读结果45.void check_start(void); //起跑线检测函数46.void car_position(void); //计算car_positn47.void angle(void); //计算转角48.void speed(void); //计算速度49.void driver(void); //驱动50.void pre_start(void);51.void delay(void);52.void found_start(void);53.void stop(void);54.void pid(void);55.unsigned int absolute(int);56.//========================main loop============================57.void main(void)58.{59. data_init(); //设置基本数据60. crg_init(); //锁向环初始化61. ect_init(); //ECT62. pwm_init(); //初始化PWM63. pre_start();64. EnableInterrupts;65. for(;;)66. {67.sam_position(); //读采样值68.check_start(); //检测起跑线69.car_position(); //计算car_positn70.angle(); //计算转角71.speed(); //计算速度72.driver(); //拐弯驱动73. }74.}75.//--------------------data_init--------------------76.void data_init(void)77.{78. start_line_acc=0;79. finish_flag=0;80. DDRA=0X00;81. DDRB=0X00;82. times=0;83.}84.//-------------------pre_start------------------85.void pre_start(void)86.{87.unsigned int i;88.PWMDTY01=Angle_Center;89.PWMDTY67=0;90.for(i=0;i<10;i++) delay();91.PWMDTY23=0;92.}93.//----------------------crg_init-------------------94.void crg_init(void)95.{96.SYNR=0x02;97.REFDV=0x01;98.while((CRGFLG & 0x08)==0 );99.CLKSEL =0x80;100.}101.//--------------------pwm_init------------------------102.void pwm_init(void)103. {104.PWMCTL=0xB0; // 设置通道76、32、10级连105.PWME=0x00; // 通道禁止输出;106.PWMPRCLK=0x12;//预分频:A_CLK=busclk/2^2=6M B_CLK=BUSCLK/2^1=12M 107.PWMSCLA=0x01; //SA_CLK=A_CLK/(2*1)==3MHz108.PWMSCLB=0X01; //SB_CLK=B_CLK/(2*1)==6MHz109.PWMPOL=0x8A; //极性选择起始为高电平;110.PWMCLK=0x8A; //PWM01 选择SA_CLK PWM23 67选择SB_CLK111.PWMCNT0=0x00;112.PWMCNT1=0x00;113.PWMCNT2=0x00;114.PWMCNT3=0x00;115.PWMCNT6=0x00;116.PWMCNT7=0x00;117.PWMPER01=60000; // 周期==(1/3M)*(60000)=20ms118.PWMPER23=10000; // F=6M/10000==600Hz119.PWMPER67=10000; // F=6M/10000==600Hz120.PWMCAE=0x00; //左对齐方式121.PWME=0x82; // 通道1,7输出使能;122.}123.//-----------------------ect_init-------------------------124.void ect_init(void)125.{126.TCTL4=0x01; // Set the rising endge for PT0.127.PACN10=0x0000;128.PBCTL=0x40; //pt0 and pt1 级联成16位计数器129.MCCNT=60000; //60000*24M/16=40ms130.MCCTL=0xC7;131.TSCR1=0x10;132.}133.void sam_position(void)134.{135.sam_g[1]= PORTA_PA4;136.sam_g[2]= PORTA_PA3;137.sam_g[3]= PORTA_PA2;138.sam_g[4]= PORTA_PA1;139.sam_g[5]= PORTA_PA0;140.sam_g[6]= PORTB_PB0;141.sam_g[7]= PORTB_PB1;142.sam_g[8]= PORTB_PB2;143.sam_g[9]= PORTB_PB3;144.sam_g[10]= PORTB_PB4;145.sam_g[11]= PORTB_PB5;146.sam_g[12]= PORTB_PB6;147.sam_g[13]= PORTB_PB7;148.}149.//----------------------check_start---------------------150.void check_start(void)151.{152.unsigned char i,j=0;153.start_flag=0;154.for(i=1;i<14;i++)155.if(sam_g^sam_g[i+1])156. j++;157. if(j>=4)158. {159. if(sam_g[5] &&((!sam_g[4])&&(!sam_g[6])) &&((!sam_g[3])&&(!sam_g[7]))&&(sam_g[1]&&sam_g[10])160.) start_flag=1;161.else if(sam_g[5]&&sam_g[6] &&((!sam_g[4])&&(!sam_g[7]))&&((!sam_g[3])&&(!sam_g[8]))&&(sam_g[1]&&sam_g[10])162.) start_flag=1;163.else if( sam_g[6] &&((!sam_g[5])&&(!sam_g[7])) &&((!sam_g[4])&&(!sam_g[8])) &&(sam_g[1]&&sam_g[11])164.) start_flag=1;165.else if( sam_g[6]&&sam_g[7] &&((!sam_g[5])&&(!sam_g[8])) &&((!sam_g[4])&&(!sam_g[9])) &&(sam_g[2]&&sam_g[11])166.) start_flag=1;167.else if( sam_g[7] &&((!sam_g[6])&&(!sam_g[8])) &&((!sam_g[5])&&(!sam_g[9])) &&(sam_g[2]&&sam_g[12])168.) start_flag=1;169.else if( sam_g[7]&&sam_g[8] &&((!sam_g[6])&&(!sam_g[9]))&&((!sam_g[5])&&(!sam_g[10])) &&(sam_g[3]&&sam_g[12])170.) start_flag=1;171.else if( sam_g[8] &&((!sam_g[7])&&(!sam_g[9])) &&((!sam_g[6])&&(!sam_g[10])) &&(sam_g[3]&&sam_g[13])172.) start_flag=1;173.else if( sam_g[8]&&sam_g[9]&&((!sam_g[7])&&(!sam_g[10])) &&((!sam_g[6])&&(!sam_g[11])) &&(sam_g[4]&&sam_g[13])174.) start_flag=1;175.else if( sam_g[9] &&((!sam_g[8])&&(!sam_g[10])) &&((!sam_g[7])&&(!sam_g[11])) &&(sam_g[4]&&sam_g[13])176.) start_flag=1;177.}178.if(start_flag)179. art_count++;180.else181. art_count=0;182.if(start_count==2)183.{184.found_start();185.start_count=0;186.}187.if(start_line_acc==2)188.{189.finish_flag=1;190.}191.}192.//--------------------------car_position------------------------。
飞思卡尔智能车摄像头组技术报告 (2)
第十届“飞思卡尔”杯全国大学生智能汽车竞赛技术报告摘要本文设计的智能车系统以K60微控制器为核心控制单元,基于CCD摄像头的图像采样获取赛道图像信息,提取赛道中心线,计算出小车与黑线间的位置偏差,采用PD方式对舵机转向进行反馈控制。
使用PID控制算法调节驱动电机的转速,结合特定算法分析出前方赛道信息实现对模型车运动速度的闭环控制。
为了提高模型车的速度和稳定性,我们用C++开发了仿真平台、蓝牙串口模块、SD卡模块、键盘液晶模块等调试工具,通过一系列的调试,证明该系统设计方案是确实可行的。
关键词:K60,CCD摄像头,二值化,PID控制,C++仿真,SD卡AbstractIn this paper, we will design a intelligent vehicle system based on MC56F8366 as the micro-controller unit. using the CCD image sensor sampling to the track image information to extract the track line center, to calculate the positional deviation between the car with the black line, the use of PD on the rudder. The machine turned to the feedback control. We use PID control algorithm to adjust the speed of the drive motor, combined with specific algorithms to achieve closed-loop control of the movement speed of the model car in front of the track. In order to improve the speed and stability of the model car, we use the C++ to develop a simulation platform, Bluetooth serial module, SD card module, keyboard, LCD modules, debugging tools. Through a series of debugging, the system design is feasible.Key words: K60,CCD_camera, binaryzation, PID control, C++ simulation, SD card目录第1章引言................................................................................... - 1 - 第2章系统总体设计................................................................ - 2 - 2.1 系统分析..................................................................................... - 2 - 2.2 车模整体布局............................................................................. - 3 - 2.3 本章小结....................................................................................... - 4 - 第3章系统机械设计及实现................................................... - 5 - 3.1 前轮定位的调整......................................................................... - 5 -3.1.1主销内倾..............................................................................- 6 -3.1.2 后倾角.................................................................................- 6 -3.1.3 内倾角.................................................................................- 7 - 3.2 舵机安装....................................................................................... - 8 -3.2.1 左右不对称问题的发现与解决........................................- 10 - 3.3 编码器的安装............................................................................ - 10 - 3.4 摄像头安装.................................................................................- 11 -3.4.1 偏振镜的使用......................................................................- 12 -3.4.2 摄像头的标定......................................................................- 12 - 3.5 摄像头的选用.............................................................................- 13 - 3.6 红外接收装置.............................................................................- 14 -3.7 防止静电复位.............................................................................- 15 - 3.8 本章小结.......................................................................................- 15 - 第4章硬件电路系统设计及实现 ...................................... - 16 -4.1 硬件设计方案............................................................................- 16 - 4.2 电源稳压......................................................................................- 17 - 4.3 电机驱动......................................................................................- 18 - 4.4 图像处理部分............................................................................- 19 -4.4.1 摄像头升压电路.............................................................- 19 -4.4.2 视频分离电路.................................................................- 19 -4.4.3 硬件二值化.....................................................................- 19 - 4.5 灯塔电路......................................................................................- 21 - 4.6 本章小结......................................................................................- 21 -第5章系统软件设计.............................................................. - 22 -5.1 软件流程图...............................................................................- 22 - 5.2 算法新思路...............................................................................- 23 -5.2.1中心线提取.......................................................................- 23 -5.2.2 直角检测........................................................................... - 24 -5.2.3 单线检测......................................................................... - 24 - 5.3 舵机控制.....................................................................................- 25 - 5.4 速度控制.....................................................................................- 26 - 5.5 PID算法....................................................................................- 26 - 5.6 路径优化.....................................................................................- 31 -第6章系统联调...................................................................... - 33 - 6.1 开发工具.................................................................................... - 33 - 6.2 无线调试蓝牙模块及蓝牙上位机..........................................- 33 - 6.3 键盘加液晶调试......................................................................- 34 - 6.4 TF卡调试模块.........................................................................- 34 -6.4.1 TF卡.............................................................................- 34-6.4.2 SDCH卡 .........................................................................- 35 -6.4.3 软件实现.......................................................................- 36 - 6.5 C++上位机设计........................................................................- 36 - 6.6 电源放电模块...........................................................................- 38-6.6.1 镍镉电池记忆效应…………………………………….. - 39-6.6.2 放电及电池性能检测设备…………………………….. - 39- 6.7 本章小结....................................................................................- 40 - 第7章模型车技术参数........................................................ - 41 - 第8章总结............................................................................... - 42 - 参考文献...................................................................................... - 44 -第1章引言在半导体技术日渐发展的今天,电子技术在汽车中的应用越来广泛,汽车智能化已成为行业发展的必然趋势。
C语言实现控制电机加减速正反转(飞思卡尔C代码)
用单片机控制直流电动机的正反转、加减速的程序如何用C语言写参考一下这个例子吧。
#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit PW1=P2^0 ;sbit PW2=P2^1 ; //控制电机的两个输入sbit accelerate=P2^2 ; //调速按键sbit stop=P2^3 ; //停止按键sbit left=P2^4 ; //左转按键sbit right=P2^5 ; //右转按键#define right_turn PW1=0;PW2=1 //顺时针转动#define left_turn PW1=1;PW2=0 //逆向转动#define end_turn PW1=1;PW2=1 //停转uint t0=25000,t1=25000; //初始时占空比为50%uint a=25000; // 设置定时器装载初值 25ms 设定频率为20Hz uchar flag=1; //此标志用于选择不同的装载初值uchar dflag; //左右转标志uchar count; //用来标志速度档位void keyscan(); //键盘扫描void delay(uchar z);void time_init(); //定时器的初始化void adjust_speed(); //通过调整占空比来调整速度//**********************************//void main(){time_init(); //定时器的初始化while(1){keyscan(); //不断扫描键盘程序,以便及时作出相应的响应}}//*************************************//void timer0() interrupt 1 using 0{if(flag){flag=0;end_turn;a=t0; //t0的大小决定着低电平延续时间TH0=(65536-a)/256;TL0=(65536-a)%256; //重装载初值}else{flag=1; //这个标志起到交替输出高低电平的作用if(dflag==0){right_turn; //右转}else{left_turn; //左转}a=t1; //t1的大小决定着高电平延续时间TH0=(65536-a)/256;TL0=(65536-a)%256; //重装载初值}}void time_init(){TMOD=0x01; //工作方式寄存器软件起动定时器定时器功能方式1 定时器0TH0=(65536-a)/256;TL0=(65536-a)%256; //装载初值ET0=1; //开启定时器中断使能EA=1; // 开启总中断TR0=0;}//****************************************//void delay(uchar z) //在12M下延时z毫秒{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}//******************************//void keyscan(){if(stop==0){TR0=0; //关闭定时器0 即可停止转动 end_turn;}if(left==0){TR0=1;dflag=1; //转向标志置位则左转}if(right==0){TR0=1;dflag=0; //转向标志复位则右转}if(accelerate==0){delay(5) ; //延时消抖if(accelerate==0){while(accelerate==0) ; //等待松手count++;if(count==1){t0=20000;t1=30000; //占空比为百分之60}if(count==2){t0=15000;t1=35000; //占空比为百分之70}if(count==3){t0=10000;t1=40000; //占空比为百分之80}if(count==4){t0=5000;t1=45000; //占空比为百分之90}if(count==5){count=0;}}}}功能特点:1)总线速度高达40 M Hz,CAN总线:3个1Mbps的CAN总线,兼容CAN2.0 A/B;2)128 KB程序Flash和8 KB DataFlash,用于实现程序和数据存储,均带有错误校正码(E CC);3)可配置A/D:16通道模数转换器;可选8位10位和12位精度,3μs的转换时间4)内嵌MS CAN模块用于CAN节点应用,内嵌支持LIN协议的增强型SIC模块和SPI模块;5)4通道16位计数器,CRG时钟和复位发生器:锁相环、看门狗、实时中断;增强型捕捉定时器;6)出色的低功耗特性,带有中断唤醒功能的10,实现唤醒休眠系统的功能;7)通道PWM:8位8通道或16位4通道PWM,易于实现电机控制。
飞思卡尔智能车程序代码
#define flag 1;
extern uchar cflag;
extern int i,j,m,n;
extern byte cs[40][60];
/*-----------------------*/
/*-------初始化----------*/
void InputInit(){
#pragma TRAP_PROC
void IRQ_ISR()
{
TIE_C1I=1; ;
//DDRB=0XFF;
//PORTB=0XF0;
//while(1);
i=0;
j=0;
}
#pragma CODE_SEG DEFAULT
#pragma CODE_SEG NON_BANKED
#pragma TRAP_PROC
TIE_C1I=0 ; //channel 0 interrupt DISable
TIOS_IOS1=0 ; //channel 0 input capture
TCTL4_EDG1A=1;
TCTL4_EDG1B=0;
}
/*-----------------------*/
/*--中断初始化--------------------*/
void init_IRQ() {
INTCR_IRQE=1; // IRQ select edge sensitive only
INTCR_IRQEN=1; // external IRQ enable
}
/*------ADT初始化--------------*/
void ADCInit(void)
void linenihe(void);
飞思卡尔智能车完整程序
#include <hidef.h> /* common defines and macros */#include <mc9s12dg128.h> /* derivative information */ #include "lib.c"#include "funtion.h"#pragma LINK_INFO DERIV ATIVE "mc9s12dg128b"void s_ini(void) //系统初始化{uchar tmp;SYNR=3;REFDV=1;PLLCTL=0x50;delay(100);CLKSEL|=0x80; //超频到48M, 总线24M// INITRG = 0x00; /* lock registers block to 0x0000 */// INITRM = 0x39; /* lock Ram to end at 0x3FFF */// INITEE = 0x09; /* lock EEPROM block to end at 0x0fff */ delay(100);PORTB=0xff;DDRB=0xff;DDRA=0x00; //A口设置为输入PTH=0x00;DDRH=0x68; //PH1=inputPERH=0x97; //enable pullPPSH=0x80; //PH7,PH6,PH5 pull up, PH4 pull down PIEH=0x00; //使能遥控中断PH7PTP =0x00;DDRP=0x30; //PP4,PP5 outputDDRA=0x00;PUCR=0x01; //Port A enable pull upPTJ=0x00;DDRJ=0x00;PERJ=0x00; //diable pullPPSJ=0x80;PIEJ=0xc0; //enable PJ interruptPTT=0x00;DDRT=0x00; //PT7-PT4 =inputPERT=0x40; //enable pull for PT6// PACN3=0x00;// PACN2=0x00;// PACTL=0x40; //enable pulse couter B// DL YCT=0x00; //TIOS=0x80; //ch 7 compare modeOC7M=0x00;OC7D=0x00;// PACTL=0x74;TSCR2=0x0f; //when ch7 compare rst pre div =128 TC7=50000; //timer for 200mS //*/TSCR1=0x80; //enable timerTCTL1=0x00;TCTL2=0x00;TCTL3=0x20;TCTL4=0x00; //通道6下降沿输入捕捉TIE =0xC0; //中断使能ini_at45(); //初始化SPI0PWME=0xc3; //enable ch1, ch7PWMPOL=0xc3; //high level effectPWMDTY6=(uchar)(3000>>8);PWMDTY7=(uchar)(3000&0x00ff); //占空比PWMPER6=(uchar)(40000>>8); // 舵机PWMPER7=(uchar)(40000&0x00ff); //周期PWMDTY0=(uchar)(0>>8);PWMDTY1=(uchar)(0&0x00ff); //占空比// PWMPER0=(uchar)(2000>>8); //电机PWMPER1=(uchar)(2000&0x00ff); //周期PWMCLK=0x00;PWMPRCLK=0x40; //SB=Fck/1 SA=Fck/8PWMCTL=0x90; //4_16 bit PWM //*/SCI0BDH=0; //串口0初始化SCI0BDL=35; //set bandrate=57600bpsSCI0CR1=0x00;SCI0CR2=0x2c; //enable to sent and receivetmp=SCI0SR1;A TD0CTL2=0xc0; //enable ATD, interruptA TD0CTL3=0x08;A TD0CTL4=0x80; //8bit,A TD1CTL2=0xc0; //enable ATD, interruptA TD1CTL3=0x08;A TD1CTL4=0x80; //8bit,A TD0DIEN=0x00; //AD口数字输入使能,使能CCD输入A TD1DIEN=0x80; //CCD二元输入ECLKDIV=0x5C; //EEPROM时钟分频器INTCR=0xc0; //行同步中断, 下降沿触发,delay(10);SE_s; //舵机供电}interrupt 20 void sci0(void) //SCI0 interrupt{uchar sta,das;sta=SCI0SR1; //read the statedas=SCI0DRL;if(sta&0x40) //sent finish{}if(sta&0x20) //receve a data{speed(das*8);SCI0DRL=das;}}interrupt 15 void ch7(void) //ch7 interrupt 266mS {TFLG1=0x80; //clr flagif(m_en) //LED falshPORTB^=0xf0;}void choice(void) //choice a funtion{uchar kv;uchar pp=0;uchar tmp=0;V1: kv=0;wu(CN1[0],CN1[1],CN1[2],CN1[3]); //displayset(2);go(0,pp); //flashfor(;;) //loop{kv=key();if(kv==5&&pp) //lastpp--,go(0,pp);else if(kv==6&&pp<3) //nextpp++,go(0,pp);if(kv==8||kv==10) //enter{if(pp==0) //进入比赛{match();goto V1;}else if(pp==1) //传感受器测方式{text();goto V1;}else if(pp==2) //CCD 测试{t_ccd();goto V1;}else if(pp==3) //参数设定{setting();goto V1;}} //*/}}void main(void) {/* put your own code here */volatile uint t1=0;s_ini(); //系统初始化EnableInterrupts;get_s(); //获取设定参数choice(); //shoicefor(;;) {} /* wait forever *//* please make sure that you never leave this function */ }/****************************************************************************** FILE : datapage.cPURPOSE : paged data access runtime routinesMACHINE : Freescale 68HC12 (Target)LANGUAGE : ANSI-CHISTORY : 21.7.96 first version created******************************************************************************/#include "hidef.h"#include "non_bank.sgm"#include "runtime.sgm"#ifndef __HCS12X__ /* it's different for the HCS12X. See the text below at the #else // __HCS12X__ *//*According to the -Cp option of the compiler the__DPAGE__, __PPAGE__ and __EPAGE__ macros are defined.If none of them is given as argument, then no page accesses should occur andthis runtime routine should not be used !To be on the save side, the runtime routines are created anyway.If some of the -Cp options are given an adapted versions which only covers theneeded cases is produced.*//* if no compiler option -Cp is given, it is assumed that all possible are given : *//* Compile with option -DHCS12 to activate this code */#if defined(HCS12) || defined(_HCS12) || defined(__HCS12__) /* HCS12 family has PPAGE register only at 0x30 */#define PPAGE_ADDR (0x30+REGISTER_BASE)#ifndef __PPAGE__ /* may be set already by option -CPPPAGE */#define __PPAGE__#endif/* Compile with option -DDG128 to activate this code */#elif defined DG128 /* HC912DG128 derivative has PPAGE register only at 0xFF */#define PPAGE_ADDR (0xFF+REGISTER_BASE)#ifndef __PPAGE__ /* may be set already by option -CPPPAGE */#define __PPAGE__#endif#elif defined(HC812A4)/* all setting default to A4 already */#endif#if !defined(__EPAGE__) && !defined(__PPAGE__) && !defined(__DPAGE__)/* as default use all page registers */#define __DPAGE__#define __EPAGE__#define __PPAGE__#endif/* modify the following defines to your memory configuration */#define EPAGE_LOW_BOUND 0x400u#define EPAGE_HIGH_BOUND 0x7ffu#define DPAGE_LOW_BOUND 0x7000u#define DPAGE_HIGH_BOUND 0x7fffu#define PPAGE_LOW_BOUND (DPAGE_HIGH_BOUND+1)#define PPAGE_HIGH_BOUND 0xBFFFu#define REGISTER_BASE 0x0u#ifndef DPAGE_ADDR#define DPAGE_ADDR (0x34u+REGISTER_BASE)#endif#ifndef EPAGE_ADDR#define EPAGE_ADDR (0x36u+REGISTER_BASE)#endif#ifndef PPAGE_ADDR#define PPAGE_ADDR (0x35u+REGISTER_BASE)#endif/*The following parts about the defines are assumed in the code of _GET_PAGE_REG :- the memory region controlled by DPAGE is above the area controlled by the EPAGE andbelow the area controlled by the PPAGE.- the lower bound of the PPAGE area is equal to be the higher bound of the DPAGE area + 1*/#if EPAGE_LOW_BOUND >= EPAGE_HIGH_BOUND || EPAGE_HIGH_BOUND >= DPAGE_LOW_BOUND || DPAGE_LOW_BOUND >= DPAGE_HIGH_BOUND || DPAGE_HIGH_BOUND >= PPAGE_LOW_BOUND || PPAGE_LOW_BOUND >= PPAGE_HIGH_BOUND#error /* please adapt _GET_PAGE_REG for this non default page configuration */#endif#if DPAGE_HIGH_BOUND+1 != PPAGE_LOW_BOUND#error /* please adapt _GET_PAGE_REG for this non default page configuration */#endif/* this module does either control if any access is in the bounds of the specified page or *//* ,if only one page is specified, just use this page. *//* This behavior is controlled by the define USE_SEVERAL_PAGES. *//* If !USE_SEVERAL_PAGES does increase the performance significantly *//* NOTE : When !USE_SEVERAL_PAGES, the page is also set for accesses outside of the area controlled *//* by this single page. But this is should not cause problems because the page is restored to the old value before any other access could occur */#if !defined(__DPAGE__) && !defined(__EPAGE__) && !defined(__PPAGE__)/* no page at all is specified *//* only specifying the right pages will speed up these functions a lot */#define USE_SEVERAL_PAGES 1#elif defined(__DPAGE__) && defined(__EPAGE__) || defined(__DPAGE__) && defined(__PPAGE__) || defined(__EPAGE__) && defined(__PPAGE__)/* more than one page register is used */#define USE_SEVERAL_PAGES 1#else#define USE_SEVERAL_PAGES 0#if defined(__DPAGE__) /* check which pages are used */#define PAGE_ADDR PPAGE_ADDR#elif defined(__EPAGE__)#define PAGE_ADDR EPAGE_ADDR#elif defined(__PPAGE__)#define PAGE_ADDR PPAGE_ADDR#else /* we do not know which page, decide it at runtime */#error /* must not happen */#endif#endif#if USE_SEVERAL_PAGES /* only needed for several pages support *//*--------------------------- _GET_PAGE_REG --------------------------------Runtime routine to detect the right register depending on the 16 bit offset partof an address.This function is only used by the functions below.Depending on the compiler options -Cp different versions of _GET_PAGE_REG are produced.Arguments :- Y : offset part of an addressResult :if address Y is controlled by a page register :- X : address of page register if Y is controlled by an page register- Zero flag cleared- all other registers remain unchangedif address Y is not controlled by a page register :- Zero flag is set- all registers remain unchanged--------------------------- _GET_PAGE_REG ----------------------------------*/#if defined(__DPAGE__)#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEstatic void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */__asm {L_DPAGE:CPY #DPAGE_LOW_BOUND ;// test of lower bound of DPAGE#if defined(__EPAGE__)BLO L_EPAGE ;// EPAGE accesses are possible#elseBLO L_NOPAGE ;// no paged memory below accesses#endifCPY #DPAGE_HIGH_BOUND ;// test of higher bound DPAGE/lower bound PPAGE#if defined(__PPAGE__)BHI L_PPAGE ;// EPAGE accesses are possible#elseBHI L_NOPAGE ;// no paged memory above accesses#endifFOUND_DPAGE:LDX #DPAGE_ADDR ;// load page register address and clear zero flagRTS#if defined(__PPAGE__)L_PPAGE:CPY #PPAGE_HIGH_BOUND ;// test of higher bound of PPAGEBHI L_NOPAGEFOUND_PPAGE:LDX #PPAGE_ADDR ;// load page register address and clear zero flagRTS#endif#if defined(__EPAGE__)L_EPAGE:CPY #EPAGE_LOW_BOUND ;// test of lower bound of EPAGEBLO L_NOPAGECPY #EPAGE_HIGH_BOUND ;// test of higher bound of EPAGEBHI L_NOPAGEFOUND_EPAGE:LDX #EPAGE_ADDR ;// load page register address and clear zero flagRTS#endifL_NOPAGE:ORCC #0x04 ;// sets zero flagRTS}}#else /* !defined(__DPAGE__) */#if defined( __PPAGE__ )#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEstatic void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */__asm {L_PPAGE:CPY #PPAGE_LOW_BOUND ;// test of lower bound of PPAGE#if defined( __EPAGE__ )BLO L_EPAGE#elseBLO L_NOPAGE ;// no paged memory below#endifCPY #PPAGE_HIGH_BOUND ;// test of higher bound PPAGEBHI L_NOPAGEFOUND_PPAGE:LDX #PPAGE_ADDR ;// load page register address and clear zero flagRTS#if defined( __EPAGE__ )L_EPAGE:CPY #EPAGE_LOW_BOUND ;// test of lower bound of EPAGEBLO L_NOPAGECPY #EPAGE_HIGH_BOUND ;// test of higher bound of EPAGEBHI L_NOPAGEFOUND_EPAGE:LDX #EPAGE_ADDR ;// load page register address and clear zero flagRTS#endifL_NOPAGE: ;// not in any allowed page area;// its a far access to a non paged variableORCC #0x04 ;// sets zero flagRTS}}#else /* !defined(__DPAGE__ ) && !defined( __PPAGE__) */#if defined(__EPAGE__)#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEstatic void NEAR _GET_PAGE_REG(void) { /*lint -esym(528, _GET_PAGE_REG) used in asm code */__asm {L_EPAGE:CPY #EPAGE_LOW_BOUND ;// test of lower bound of EPAGEBLO L_NOPAGECPY #EPAGE_HIGH_BOUND ;// test of higher bound of EPAGEBHI L_NOPAGEFOUND_EPAGE:LDX #EPAGE_ADDR ;// load page register address and clear zero flagRTSL_NOPAGE: ;// not in any allowed page area;// its a far access to a non paged variableORCC #0x04 ;// sets zero flagRTS}}#endif /* defined(__EPAGE__) */#endif /* defined(__PPAGE__) */#endif /* defined(__DPAGE__) */#endif /* USE_SEVERAL_PAGES *//*--------------------------- _SET_PAGE --------------------------------Runtime routine to set the right page register. This routine is used if the compilerdoes not know the right page register, i.e. if the option -Cp is used for more thanone pageregister or if the runtime option is used for one of the -Cp options.Arguments :- offset part of an address in the Y register- page part of an address in the B registerResult :- page part written into the correct page register.- the old page register content is destroyed- all processor registers remains unchanged--------------------------- _SET_PAGE ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _SET_PAGE(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGESTAB 0,X ;// set page registerL_NOPAGE:PULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {STAB PAGE_ADDR ;// set page registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _LOAD_FAR_8 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address in the B registerResult :- value to be read in the B register- all other registers remains unchanged- all page register still contain the same value--------------------------- _LOAD_FAR_8 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _LOAD_FAR_8(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHA ;// save A registerLDAA 0,X ;// save page registerSTAB 0,X ;// set page registerLDAB 0,Y ;// actual load, overwrites pageSTAA 0,X ;// restore page registerPULA ;// restore A registerPULX ;// restore X registerRTSL_NOPAGE:LDAB 0,Y ;// actual load, overwrites pagePULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHA ;// save A registerLDAA PAGE_ADDR ;// save page registerSTAB PAGE_ADDR ;// set page registerLDAB 0,Y ;// actual load, overwrites pageSTAA PAGE_ADDR ;// restore page registerPULA ;// restore A registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _LOAD_FAR_16 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address in the B registerResult :- value to be read in the Y register- all other registers remains unchanged- all page register still contain the same value--------------------------- _LOAD_FAR_16 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _LOAD_FAR_16(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHA ;// save A registerLDAA 0,X ;// save page registerSTAB 0,X ;// set page registerLDY 0,Y ;// actual load, overwrites addressSTAA 0,X ;// restore page registerPULA ;// restore A registerPULX ;// restore X registerRTSL_NOPAGE:LDY 0,Y ;// actual load, overwrites addressPULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHA ;// save A registerLDAA PAGE_ADDR ;// save page registerSTAB PAGE_ADDR ;// set page registerLDY 0,Y ;// actual load, overwrites addressSTAA PAGE_ADDR ;// restore page registerPULA ;// restore A registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _LOAD_FAR_24 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument. Arguments :- offset part of an address in the Y register- page part of an address in the B registerResult :- value to be read in the Y:B registers- all other registers remains unchanged- all page register still contain the same value--------------------------- _LOAD_FAR_24 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _LOAD_FAR_24(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHA ;// save A registerLDAA 0,X ;// save page registerSTAB 0,X ;// set page registerLDAB 0,Y ;// actual load, overwrites page of addressLDY 1,Y ;// actual load, overwrites offset of addressSTAA 0,X ;// restore page registerPULA ;// restore A registerPULX ;// restore X registerRTSL_NOPAGE:LDAB 0,Y ;// actual load, overwrites page of addressLDY 1,Y ;// actual load, overwrites offset of addressPULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHA ;// save A registerLDAA PAGE_ADDR ;// save page registerSTAB PAGE_ADDR ;// set page registerLDAB 0,Y ;// actual load, overwrites page of addressLDY 1,Y ;// actual load, overwrites offset of addressSTAA PAGE_ADDR ;// restore page registerPULA ;// restore A registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _LOAD_FAR_32 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address in the B registerResult :- low 16 bit of value to be read in the D registers- high 16 bit of value to be read in the Y registers- all other registers remains unchanged- all page register still contain the same value--------------------------- _LOAD_FAR_32 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _LOAD_FAR_32(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGELDAA 0,X ;// save page registerPSHA ;// put it onto the stackSTAB 0,X ;// set page registerLDD 2,Y ;// actual load, low wordLDY 0,Y ;// actual load, high wordMOVB 1,SP+,0,X ;// restore page registerPULX ;// restore X registerRTSL_NOPAGE:LDD 2,Y ;// actual load, low wordLDY 0,Y ;// actual load, high wordPULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {LDAA PAGE_ADDR ;// save page registerPSHA ;// put it onto the stackSTAB PAGE_ADDR ;// set page registerLDD 2,Y ;// actual load, low wordLDY 0,Y ;// actual load, high wordMOVB 1,SP+,PAGE_ADDR ;// restore page registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _STORE_FAR_8 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address in the B register- value to be stored in the B registerResult :- value stored at the address- all registers remains unchanged- all page register still contain the same value--------------------------- _STORE_FAR_8 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _STORE_FAR_8(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHB ;// save B registerLDAB 0,X ;// save page registerMOVB 0,SP, 0,X ;// set page registerSTAA 0,Y ;// store the value passed in ASTAB 0,X ;// restore page registerPULB ;// restore B registerPULX ;// restore X registerRTSL_NOPAGE:STAA 0,Y ;// store the value passed in APULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHB ;// save A registerLDAB PAGE_ADDR ;// save page registerMOVB 0,SP,PAGE_ADDR ;// set page registerSTAA 0,Y ;// store the value passed in ASTAB PAGE_ADDR ;// restore page registerPULB ;// restore B registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _STORE_FAR_16 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address in the B register- value to be stored in the X registerResult :- value stored at the address- all registers remains unchanged- all page register still contain the same value--------------------------- _STORE_FAR_16 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _STORE_FAR_16(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHALDAA 0,X ;// save page registerSTAB 0,X ;// set page registerMOVW 1,SP,0,Y ;// store the value passed in XSTAA 0,X ;// restore page registerPULA ;// restore A registerPULX ;// restore X registerRTSL_NOPAGE:STX 0,Y ;// store the value passed in XPULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHA ;// save A registerLDAA PAGE_ADDR ;// save page registerSTAB PAGE_ADDR ;// set page registerSTX 0,Y ;// store the value passed in XSTAA PAGE_ADDR ;// restore page registerPULA ;// restore A registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _STORE_FAR_24 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address in the B register- value to be stored in the X:A registers (X : low 16 bit, A : high 8 bit)Result :- value stored at the address- all registers remains unchanged- all page register still contain the same value--------------------------- _STORE_FAR_24 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _STORE_FAR_24(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHALDAA 0,X ;// save page registerSTAB 0,X ;// set page registerMOVW 1,SP, 1,Y ;// store the value passed in XMOVB 0,SP, 0,Y ;// store the value passed in ASTAA 0,X ;// restore page registerPULA ;// restore A registerPULX ;// restore X registerRTSL_NOPAGE:STX 1,Y ;// store the value passed in XSTAA 0,Y ;// store the value passed in XPULX ;// restore X registerRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHA ;// save A registerLDAA PAGE_ADDR ;// save page registerSTAB PAGE_ADDR ;// set page registerMOVB 0,SP, 0,Y ;// store the value passed in ASTX 1,Y ;// store the value passed in XSTAA PAGE_ADDR ;// restore page registerPULA ;// restore A registerRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _STORE_FAR_32 --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of an address in the Y register- page part of an address is on the stack at 3,SP (just below the return address)- value to be stored in the X:D registers (D : low 16 bit, X : high 16 bit)Result :- value stored at the address- all registers remains unchanged- the page part is removed from the stack- all page register still contain the same value--------------------------- _STORE_FAR_32 ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _STORE_FAR_32(void) {#if USE_SEVERAL_PAGES__asm {PSHX ;// save X register__PIC_JSR(_GET_PAGE_REG)BEQ L_NOPAGEPSHDLDAA 0,X ;// save page registerMOVB 6,SP, 0,X ;// set page registerMOVW 2,SP, 0,Y ;// store the value passed in X (high word)MOVW 0,SP, 2,Y ;// store the value passed in D (low word)STAA 0,X ;// restore page registerPULD ;// restore A registerBRA doneL_NOPAGE:MOVW 0,SP, 0,Y ;// store the value passed in X (high word)STD 2,Y ;// store the value passed in D (low word) done:PULX ;// restore X registerMOVW 0,SP, 1,+SP ;// move return addressRTS}#else /* USE_SEVERAL_PAGES */__asm {PSHD ;// save D registerLDAA PAGE_ADDR ;// save page registerLDAB 4,SP ;// load page part of addressSTAB PAGE_ADDR ;// set page registerSTX 0,Y ;// store the value passed in XMOVW 0,SP, 2,Y ;// store the value passed in D (low word)STAA PAGE_ADDR ;// restore page registerPULD ;// restore D registerMOVW 0,SP, 1,+SP ;// move return addressRTS}#endif /* USE_SEVERAL_PAGES */}/*--------------------------- _FAR_COPY_RC --------------------------------This runtime routine is used to access paged memory via a runtime function.It may also be used if the compiler option -Cp is not used with the runtime argument.Arguments :- offset part of the source int the X register- page part of the source in the A register- offset part of the dest int the Y register- page part of the dest in the B register- number of bytes to be copied is defined by the next 2 bytes after the return address.Result :- memory area copied- no registers are saved, i.e. all registers may be destroyed- all page register still contain the same value as before the call- the function returns after the constant defining the number of bytes to be copiedstack-structure at the loop-label:0,SP : destination offset2,SP : source page3,SP : destination page4,SP : source offset6,SP : points to length to be copied. This function returns after the sizeA usual call to this function looks like:struct Huge src, dest;; ...LDX #srcLDAA #PAGE(src)LDY #destLDAB #PAGE(dest)JSR _FAR_COPY_RCDC.W sizeof(struct Huge); ...--------------------------- _FAR_COPY_RC ----------------------------------*/#ifdef __cplusplusextern "C"#endif#pragma NO_ENTRY#pragma NO_EXIT#pragma NO_FRAMEvoid NEAR _FAR_COPY_RC(void) {#if USE_SEVERAL_PAGES__asm {DEX ;// source addr-=1, because loop counter ends at 1PSHX ;// save source offsetPSHD ;// save both pagesDEY ;// destination addr-=1, because loop counter ends at 1PSHY ;// save destination offsetLDY 6,SP ;// Load Return addressLDX 2,Y+ ;// Load Size to copySTY 6,SP ;// Store adjusted return addressloop:LDD 4,SP ;// load source offset。
飞思卡尔MC9S12XEP芯片的CAN总线代码
#define CAN_GLOBALS#include "can.h"void EEC1_Process(uint8_t OutPtr, uint8_t InPtr);void EEC2_Process(uint8_t OutPtr, uint8_t InPtr);void EEC3_Process(uint8_t OutPtr, uint8_t InPtr);void ET1_Process(uint8_t OutPtr, uint8_t InPtr);void CCVS_Process(uint8_t OutPtr, uint8_t InPtr);void LFE_Process(uint8_t OutPtr, uint8_t InPtr);void AMB_Process(uint8_t OutPtr, uint8_t InPtr);void IC1_Process(uint8_t OutPtr, uint8_t InPtr);void VEP1_Process(uint8_t OutPtr, uint8_t InPtr);void EFL_P1_Process(uint8_t OutPtr, uint8_t InPtr);void LFC_Process(uint8_t OutPtr, uint8_t InPtr);void Digit2Ascii1(uint32_t Digit, uint8_t InPtr); //一位小数void Digit2Ascii0(uint32_t Digit, uint8_t InPtr); //数字转化为ASCII码 0位小数void Digit2AsciiPos0(uint32_t Digit, uint8_t InPtr); //数字转化为ASCII码 0位小数负数uint8_t *Result;HMI_Text_Dis_tPtr HMI_Text_DisPtr;///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void CANFilterInit(uint8_t CAN){if(CAN<CANS){switch(CAN){case CAN0:CAN0IDAR0 = 0xFF;CAN0IDAR1 = 0xFF; CAN0IDAR2 = 0xFF; CAN0IDAR3 = 0xFF; CAN0IDMR0 = 0xFF; CAN0IDMR1 = 0xFF; CAN0IDMR2 = 0xFF; CAN0IDMR3 = 0xFF; CAN0IDAR4 = 0xFF; CAN0IDAR5 = 0xFF; CAN0IDAR6 = 0xFF; CAN0IDAR7 = 0xFF; CAN0IDMR4 = 0xFF; CAN0IDMR5 = 0xFF; CAN0IDMR6 = 0xFF; CAN0IDMR7 = 0xFF; break;case CAN1:CAN1IDAR0 = 0xFF; CAN1IDAR1 = 0xFF; CAN1IDAR2 = 0xFF; CAN1IDAR3 = 0xFF; CAN1IDMR0 = 0xFF; CAN1IDMR1 = 0xFF; CAN1IDMR2 = 0xFF; CAN1IDMR3 = 0xFF; CAN1IDAR4 = 0xFF; CAN1IDAR5 = 0xFF; CAN1IDAR6 = 0xFF; CAN1IDAR7 = 0xFF; CAN1IDMR4 = 0xFF; CAN1IDMR5 = 0xFF; CAN1IDMR6 = 0xFF; CAN1IDMR7 = 0xFF; break;}}}/*--------------------------------------------------------------------------------------------------------Function:Param:Return:note----------------------------------------------------------------------------------------------------------*/void CANRxQueInit(void){CAN_RxQue.Front = 0;CAN_RxQue.Rear = 0;memset(&CAN_RxQue, 0, sizeof(CAN_RxQue));}/*--------------------------------------------------------------------------------------------------------Function: CAN0 CAN1初始化Param:Return:note----------------------------------------------------------------------------------------------------------*/CAN_EXT void CANInit(uint8_t CAN){if(CAN<CANS){switch(CAN){case CAN0:CAN0CTL1_CANE = 1; //使能CAN模块CAN0CTL1_LISTEN = 0; //除能监听模式CAN0BTR0 = CAN0BTR0_Val; //设置波特率CAN0BTR1 = CAN0BTR1_Val;CANFilterInit(CAN0); //设置验收、屏蔽滤波器CAN0CTL0_INITRQ = 0; //请求退出初始化while(CAN0CTL1_INITAK == 1){ //请求处理ing _asm(nop);}while(CAN0CTL0_SYNCH == 0){_asm(nop);}CAN0RFLG = 0xC3; //清除接收相关标志位CANRxQueInit(); //CAN中断接收队列CAN0RIER_RXFIE = 1; //接收中断允许break;case CAN1:CAN1CTL1_CANE = 1; //使能CAN模块CAN1CTL1_LISTEN = 0; //除能监听模式CAN1BTR0 = CAN1BTR0_Val; //设置波特率CAN1BTR1 = CAN1BTR1_Val;CANFilterInit(CAN1); //设置验收、屏蔽滤波器CAN1CTL0_INITRQ = 0; //请求退出初始化while(CAN1CTL1_INITAK == 1){ //请求处理ing _asm(nop);}while(CAN1CTL0_SYNCH == 0){_asm(nop);}CAN1RFLG = 0xC3; //清除接收相关标志位CANRxQueInit(); //CAN中断接收队列CAN1RIER_RXFIE = 1; //接收中断允许break;}}}/*----------------------------------------------------------------------------------------------------------Function:存储并显示把CAN_RxQue 队列里的数据存放到 FLASH 中,某些数据再存到HMI_Text_Dis_Que 队列里进行显示其中 CAN_RxQue 的ID转换为 PGNTmp 再转换为 HMI_Text_Dis_Que 显示的位置CAN_RxQue 的数据即 HMI_Text_Dis_Que 的数据起始帧命令帧终止帧都已包含Param:Return:note----------------------------------------------------------------------------------------------------------*/CAN_EXT void CANRxQueToProcess(void){ID_tPtr IDPtr;uint32_t PGNTmp;while(CAN_RxQue.Front!= CAN_RxQue.Rear) //源队列未空,可出列{IDPtr = &(CAN_RxQue.PDUs[CAN_RxQue.Front].Bits.ID); //指向出列项ID 域PGNTmp = 0;PGNTmp |= (uint8_t)(IDPtr->Bits.DP | IDPtr->Bits.R<<1);//析取DP和RPGNTmp <<= 8;PGNTmp |= (uint8_t)(IDPtr->Bits.PF0 | IDPtr->Bits.PF1<<2 | IDPtr->Bits.PF2<<5); //析取PFPGNTmp <<= 8;PGNTmp |= (uint8_t)(IDPtr->Bits.PS0 | IDPtr->Bits.PS1<<7);//析取PSif(PGNTmp == (uint16_t)PGN_FAULT_MEMORY){FAULT_flag = 1;}else{FAULT_flag = 0;}switch(PGNTmp){case (uint16_t)PGN_EEC1:EEC1_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_EEC2:EEC2_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_EEC3:EEC3_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_AMB:AMB_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_CCVS:CCVS_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear);break;case (uint16_t)PGN_ET1:ET1_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_LFE:LFE_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_EFL_P1:EFL_P1_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_IC1:IC1_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_VEP1:VEP1_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear); break;case (uint16_t)PGN_LFC: // 时间太大目前只能计算两个字节的LFC_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear);break;case (uint16_t)PGN_FAULT_MEMORY:FAULT_MEMORY_Process(CAN_RxQue.Front, HMI_Text_Dis_Que.Rear, 0, 0); //为了方便触摸屏看故障类型上下条时使用break;default:break;}CAN_RxQue.Front = (uint8_t)(CAN_RxQue.Front+1)%CAN_RXQUE_LEN;//出列一项}CANRxQueInit();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void EEC1_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t engspeed;uint32_t actualengtorque;eec1 = (EEC1_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;engspeed = (((uint32_t)swab16(eec1->EngSpeed))*12) +(((uint32_t)swab16(eec1->EngSpeed))>>1);actualengtorque = ((uint32_t)(eec1->ActualEngTorque)) * 100;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) {HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear;HMI_Text_DisPtr->CMD_Start = HMI_CMD_START;HMI_Text_DisPtr->CMD_Type = HMI_CMD_TextDIS_ASCII;HMI_Text_DisPtr->Start_Point.x = 145;HMI_Text_DisPtr->Start_Point.y = 150;Digit2Ascii0(engspeed, InPtr);HMI_Text_DisPtr->CMD_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN;}if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) {HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis + HMI_Text_Dis_Que.Rear;HMI_Text_DisPtr->Cmd_Start = HMI_CMD_START;HMI_Text_DisPtr->Cmd_Type = HMI_CMD_TEXTDIS_ASCII;HMI_Text_DisPtr->Start_Point.x = 590;HMI_Text_DisPtr->Start_Point.y = 150;if(actualengtorque<12500){actualengtorque = 12500 - actualengtorque;Digit2AsciiPos0(actualengtorque, HMI_Text_Dis_Que.Rear);}else{actualengtorque = actualengtorque - 12500;Digit2Ascii0(actualengtorque, HMI_Text_Dis_Que.Rear);}HMI_Text_DisPtr->Cmd_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void EEC2_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t accpedalpos1;eec2 = (EEC2_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;accpedalpos1 = ((uint32_t)(eec2->accpedalPos1)) * 40;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TextDIS_QUELEN) //目的队列未满,可入列{HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear; //指向入列项HMI_Text_DisPtr->CMD_Start = HMI_CMD_START; //写入命令头HMI_Text_DisPtr->CMD_Type = HMI_CMD_TEXTDIS_ASCII; //写入命令种类HMI_Text_DisPtr->Start_Point.x = 145; //文本显示位置x坐标HMI_Text_DisPtr->Start_Point.y = 315; //文本显示位置y坐标Digit2Ascii0(accpedalpos1, InPtr); //%HMI_Text_DisPtr->CMD_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void EEC3_Process(uint8_t OutPtr, uint8_t InPtr){eec3 = (EEC3_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void ET1_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t engcoolanttemp;et1 = (ET1_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;engcoolanttemp = ((uint32_t)(et1->EngCoolantTemp)) *100;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TextDIS_QUELEN) //目的队列未满,可入列{HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear; //指向入列项HMI_Text_DisPtr->CMD_Start = HMI_CMD_START; //写入命令头HMI_Text_DisPtr->CMD_Type = HMI_CMD_TEXTDIS_ASCII; //写入命令种类HMI_Text_Dis_Que.HMI_Text_Dis[InPtr].Start_Point.x = 145; //文本显示位置x坐标HMI_Text_Dis_Que.HMI_Text_Dis[InPtr].Start_Point.y = 390;if(engcoolanttemp<4000){engcoolanttemp = 4000 - engcoolanttemp;Digit2AsciiPos0(engcoolanttemp, InPtr);}else{engcoolanttemp = engcoolanttemp - 4000;Digit2Ascii0(engcoolanttemp, InPtr);}HMI_Text_DisPtr->CMD_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void CCVS_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t vehiclespeed;ccvs = (CCVS_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;vehiclespeed = (((uint32_t)swab16(ccvs->VehicleSpeed)) * 100) >> 8;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) //目的队列未满,可入列{HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear; //指向入列项HMI_Text_DisPtr->CMD_Start = HMI_CMD_START; //写入命令头HMI_Text_DisPtr->CMD_Type = HMI_CMD_TEXTDIS_ASCII; //写入命令种类HMI_Text_DisPtr->Start_Point.x = 370; //文本显示位置x坐标HMI_Text_DisPtr->Start_Point.y = 150; //文本显示位置y坐标Digit2Ascii1(vehiclespeed, InPtr); //%HMI_Text_DisPtr->CMD_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void LFE_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t engfuelrate;lfe = (LFE_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;engfuelrate = ((uint32_t)swab16(lfe->EngFuelRate)) * 5;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) {HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear;HMI_Text_DisPtr->Cmd_Start = HMI_CMD_START;HMI_Text_DisPtr->Cmd_Type = HMI_CMD_TEXTDIS_ASCII;HMI_Text_DisPtr->Start_Point.x = 370;HMI_Text_DisPtr->Start_Point.y = 365;Digit2Ascii0(engfuelrate, InPtr);HMI_Text_DisPtr->Cmd_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------static void AMB_Process(uint8_t OutPtr, uint8_t InPtr){amb = (AMB_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void IC1_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t engintakemanifold1temp; // 进气温度uint32_t engairinletpressure; //绝对增压压力ic1 = (IC1_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;engintakemanifold1temp = ((uint32_t)(ic1->EngIntakeManifold1Temp)) * 100;engairinletpressure = ((uint32_t)(ic1->EngAirInletPressure)) * 200;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TextDIS_QUELEN) //目的队列未满,可入列{HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear; //指向入列项HMI_Text_DisPtr->CMD_Start = HMI_CMD_START; //写入命令头HMI_Text_DisPtr->CMD_Type = HMI_CMD_TEXTDIS_ASCII; //写入命令种类HMI_Text_DisPtr->Start_Point.x = 370; //文本显示位置x坐标HMI_Text_DisPtr->Start_Point.y = 255;if(engintakemanifold1temp<4000){engintakemanifold1temp = 4000 - engintakemanifold1temp;Digit2AsciiPos0(engintakemanifold1temp, InPtr);}else{engintakemanifold1temp = engintakemanifold1temp - 4000;Digit2Ascii0(engintakemanifold1temp, InPtr);}HMI_Text_DisPtr->CMD_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TextDIS_QUELEN; //进列一项}if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) {HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear;HMI_Text_DisPtr->CMD_Start = HMI_CMD_START;HMI_Text_DisPtr->Cmd_Type = HMI_CMD_TEXTDIS_ASCII;HMI_Text_DisPtr->Start_Point.x = 590;//590HMI_Text_DisPtr->Start_Point.y = 255;Digit2Ascii0(engairinletpressure, HMI_Text_Dis_Que.Rear);HMI_Text_DisPtr->Cmd_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void VEP1_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t batterybotentialswitched;vep1 = (VEP1_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;batterybotentialswitched = ((uint32_t)swab16(vep1->BatteryPotentialSwitched))*5;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) {HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear;HMI_Text_DisPtr->Cmd_Start = HMI_CMD_START;HMI_Text_DisPtr->Cmd_Type = HMI_CMD_TEXTDIS_ASCII;HMI_Text_DisPtr->Start_Point.x = 590;HMI_Text_DisPtr->Start_Point.y = 365;Digit2Ascii1(batterybotentialswitched, InPtr);HMI_Text_DisPtr->Cmd_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TextDIS_QUELEN;}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void EFL_P1_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t engoilpressure;efl_p1 = (EFL_P1_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;engoilpressure = ((uint32_t)(efl_p1->EngOilPressure)) * 400;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN) //目的队列未满,可入列{HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear; //指向入列项HMI_Text_DisPtr->CMD_Start = HMI_CMD_START; //写入命令头HMI_Text_DisPtr->CMD_Type = HMI_CMD_TEXTDIS_ASCII; //写入命令种类HMI_Text_DisPtr->Start_Point.x = 145; //文本显示位置x坐标HMI_Text_DisPtr->Start_Point.y = 230; //文本显示位置y坐标Digit2Ascii0(engoilpressure, InPtr);HMI_Text_DisPtr->Cmd_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------void LFC_Process(uint8_t OutPtr, uint8_t InPtr){uint32_t engtotalfuelused;lfc = (LFC_t *)CAN_RxQue.PDUs[OutPtr].Bits.DataField;engtotalfuelused = ((uint32_t)swab32(lfc->EngTotalFuelUsed))>>1 ;if(HMI_Text_Dis_Que.Front !=(HMI_Text_Dis_Que.Rear+1)%HMI_TextDIS_QUELEN) //目的队列未满,可入列{HMI_Text_DisPtr = HMI_Text_Dis_Que.HMI_Text_Dis +HMI_Text_Dis_Que.Rear; //指向入列项HMI_Text_DisPtr->CMD_Start = HMI_CMD_START; //写入命令头HMI_Text_DisPtr->CMD_Type = HMI_CMD_TEXTDIS_ASCII; //写入命令种类HMI_Text_DisPtr->Start_Point.x = 125; //文本显示位置x坐标HMI_Text_DisPtr->Start_Point.y = 220; //文本显示位置y坐标Digit2Ascii1(engtotalfuelused, InPtr);HMI_Text_DisPtr->Cmd_End = HMI_CMD_END;HMI_Text_Dis_Que.Rear =(uint8_t)(HMI_Text_Dis_Que.Rear+1)%HMI_TEXTDIS_QUELEN; //进列一项}Record_Write();}///----------------------------------------------------------------------------------------------------------//Function://Param://Return://note///----------------------------------------------------------------------------------------------------------CAN_EXT void FAULT_MEMORY_Process(uint8_t OutPtr, uint8_t InPtr, uint8_t Touch_flag, uint16_t num){uint16_t Fault_Type;uint8_t error1[]="安全晶体管电磁阀阵列1(高边)故障"; uint8_t error2[]="安全晶体管电磁阀阵列1(低边)故障"; uint8_t error3[]="安全晶体管电磁阀阵列3(高边)故障"; uint8_t error4[]="存储器控制错误";uint8_t error5[]="看门狗控制错误";uint8_t error6[]="处理器控制错误";uint8_t error7[]="TRAP控制错误";uint8_t error8[]="5V电压控制错误";uint8_t error9[]="12V传感器电压控制错误";uint8_t error10[]="12.5V电压控制错误";uint8_t error11[]="24V电压错误";uint8_t error12[]="nvSRAM控制错误";uint8_t error13[]="nvSRAM数据控制错误";uint8_t error14[]="CAN接口初始化错误";uint8_t error15[]="SEAJ1939协议错误";uint8_t error16[]="传感器电缆堵塞";uint8_t error17[]="温度传感器。
飞思卡尔杯全国大学生智能汽车竞赛技术报告_摄像头组
第十届"飞思卡尔"杯全国大学生智能汽车竞赛技术报告第十届“飞思卡尔”杯全国大学生智能汽车竞赛技术报告学校:电子科技大学摘要本文设计的智能车系统以MK60DN512ZVLQ10微控制器为核心控制单元,通过CMOS摄像头检测赛道信息,使用模拟比较器对图像进行硬件二值化,提取黑色引导线,用于赛道识别;通过编码器检测模型车的实时速度,使用PID控制算法调节驱动电机的转速和转向舵机的角度,实现了对模型车运动速度和运动方向的闭环控制。
关键字:MK60DN512ZVLQ10,CMOS,PIDAbstractIn this paper we will design a smart car system based on MK60DN512ZVLQ10as the micro-controller unit. We use a CMOS image sensor to obtain lane image information. Then convert the original image into the binary image by the analog comparator circuit in order to extract black guide line for track identification. An inferred sensor is used to measure the car`s moving speed. We use PID control method to adjust the rotate speed of driving electromotor and direction of steering electromotor, to achieve the closed-loop control for the speed and direction.Keywords: MK60DN512ZVLQ10,CMOS,PID目录摘要 (II)Abstract (III)目录............................................................................................................................ I V 引言.. (1)第一章系统总体设计 (2)1.1系统概述 (2)1.2整车布局 (3)第二章机械系统设计及实现 (4)2.1智能车机械参数调节 (4)2.1.1 前轮调整 (4)2.1.2其他部分调整 (6)2.2底盘高度的调整 (7)2.3编码器的安装 (7)2.4舵机转向结构的调整 (8)2.5摄像头的安装 (9)第三章硬件系统设计及实现 (11)3.1 MK60DN512ZVLL10主控模块 (12)3.2电源管理模块 (12)3.3 摄像头模块 (14)3.4电机驱动模块 (15)3.5测速模块 (16)3.6陀螺仪模块 (16)3.7灯塔检测模块 (16)3.8辅助调试模块 (17)第四章软件系统设计及实现 (19)4.1赛道中心线提取及优化处理 (19)4.1.1原始图像的特点 (19)4.1.2赛道边沿提取 (20)4.1.3推算中心 (21)4.1.4路径选择 (23)4.2 PID 控制算法介绍 (23)4.2.1位置式PID (24)4.2.2增量式PID (25)4.2.3 PID参数整定 (25)4.3转向舵机的PID控制算法 (25)4.4驱动电机的PID控制算法 (26)第五章系统开发及调试工具 (27)5.1开发工具 (27)5.2上位机图像调试 (27)5.3SD卡模块 (27)5.3.1SD卡介绍 (27)5.3.2 SPI总线介绍 (28)5.3.3软件实现 (28)第六章模型车的主要技术参数 (30)结论 (31)参考文献 (I)附录A:电原理图 (II)附录B:程序源代码................................................................................................... I V引言随着科学技术的不断发展进步,智能控制的应用越来越广泛,几乎渗透到所有领域。
飞思卡尔智能车电路详解(全)
增加检测距离。但使用不当极易烧毁传感 器,因此初期使用时不推荐使用此方法。
视频分离电路 LM1881
测速传感器模块
• 霍尔传感器 • 反射式红外传感器 • 对射式红外传感器 • 测速电机 • 对加速度传感器进行积分
智能汽车
之
硬件电路设计
安徽大学 创新实验室整理
整个系统电路模块组成
• 单片机控制模块 • 黑线检测模块 • 测速模块 • 电机驱动模块 • 电源模块
单片机控制模块
黑线检测模块
• 光电组:反射式红外传感器、 激光传感器
• 摄像头组:CMOS、CCD
红外传感器RPR220
具体使用注意点
• 发光二极管部分在恒流情况下最大工作电 流为50mA。
• 电子调速器(电调) 好用,但实在太贵
L298N 输入输出
并联电路
MC33886并联电路
。。。。。。
电源模块
• 单片机系统模块电源 -- 5V(LM2940)
• 黑线检测传感器模块电源
光电 -- 5V(LM2575) 摄像头 -- 9V/12V(mc34063)
• 测速部分电源 -- 5V
• 舵机动电源 -- 电池直接供电 • 电机驱动模块电源 -- 电池直接供电
5V电源部分
LM2575芯片手册上的常用电路
二极管的额定电流值应大于最大负载电流的1.2倍,但考虑 到负载短路的情况,二极管的额定电流值应大于LM2575的最大 电流限制;另外二极管的反向电压应大于最大输入电压的1.25 倍。
LM2575芯片特点
• 优点: 转换效率高,芯片发热现象不明显,避
飞思卡尔智能车摄像头组入门指南
飞思卡尔智能车摄像头组入门指南摄像头摄像头的组成主要分为三部分:镜头、含传感器的处理芯片、外围电路板。
镜头主要就是一个凸透镜,透镜焦距越小越广角,同时桶形失真越严重;焦距越大,视角越窄,透镜越接近理想的“薄透镜”则可忽略桶形失真。
处理芯片将传感器上的电压信号按照已定义的协议输出。
外围电路主要提供电源、稳压、时钟等功能。
摄像头按照信号类型可分为模拟摄像头、数字摄像头两种。
由于单片机普通IO口只能读取数字信号,故对于模拟摄像头要设计模数转换(ATD)。
数字摄像头数据可以直接进单片机。
用模拟摄像头的缺点是要自己设计模数转换电路,同步信号分离电路。
优点是可以自行加入硬件二值化电路,即对某一个像素点只用1、0来表示黑、白。
摄像头按照传感器,可分为CCD、CMOS。
CCD成像质量好,贵。
CMOS 成像质量略差,便宜。
摄像头的选取从尽快实现,缩短开发时间的方面考虑,应购买数字摄像头。
典型的型号是OV7620(该型号是指处理芯片的型号)。
OV7620是CMOS数字摄像头,采用PAL制式,默认隔行扫描,默认YUV颜色空间输出(详见后文)。
长远考虑,应选取CCD模拟摄像头。
一来可以避免高速状态下的运动模糊,二来可以自行设计硬件二值化电路,FIFO电路等,大大降低CPU 运算压力。
摄像头信号协议介绍每秒超过24帧的连续图片即可形成动态的视频。
考虑到我国采用50Hz交流电,为了实现方便,摄像头被设计为每秒25帧,每帧耗时两个周期。
还是为了实现方便,每一帧图片被分为两半,每半帧耗时一个周期。
半帧的划分方式为:奇数行和偶数行各组成半帧。
即通常的电视机,每20ms奇数行的信息刷新一次,接下来20ms偶数行刷新一次,再20ms奇数行刷新一次……。
欧美采用60Hz交流电,摄像头每16.6ms刷新一次,被称为PAL制式。
摄像头拍摄的一帧画面被称为“一场”(field),一场又分为“奇场”和“偶场”,各称“半场”,合称“全场”。
像这样分奇偶场分别刷新的扫描方式被称作“隔行扫描”(interlace),某些摄像头支持“逐行扫描”(progressive),其意自见。
摄像头上位机说明
飞思卡尔智能车无线调试工具说明
1.上位机配置部分,选择相应的串口序号,选择波特率(推荐9600)打开串口即可
其中长为摄像头数据行,宽为列,阈值为进行简单二值化的临界值,如128,则<128显示黑。
上位机支持实时参数显示,支持图像显示,或者同时显示两者。
选中复选框即可。
2.上位机接图像接受部分
左图为原始图像,右图为二值化处理之后图像。
3.实时参数显示
其中,编码器脉冲,电机pwm ,舵机pwm 最
大显示数值为256*256,自定义数据 1234最
大显示数据256.(可用来调整pid 参数)。
4.速度曲线绘图
绘图原理是,每接收到一个编码器数值(实时参数),进行一次绘图,横坐标变化为△X,其他4值为纵坐标显示范围,如果想得到更好的显示效果,根据自身情况,调整横纵坐标即可。
5.下位机SCI初始化(如果代码不可复制,请下载Adobe Reader或SumatraPDF(推荐))
6.下位机发送部分
7.下位机接收部分
8.关于正版
试用版软件程序,功能有所限制,敬请原谅。
正版软件包括以下功能
1.简单二值化图像处理
2.曲线绘图功能全部开始(试用版仅限舵机PWM)
如欲购买正版软件,请访问/,将机器码告予店主即可。
购买用户将得到无限期技术支持和免费版本更新。
支持正版是我开发新版本的动力!谢谢。
智能车竞赛摄像头组代码
int count=0;
int st_flag=0;
int jishu=0;
//////////////////////黑线提取////////////////////
//////////////////////////////////////////////////
//CCD_state//
#define GETVSYNC 0 //获取场中断
#define GETHREF 1 //获取行中断
#define WAITVSYNC 2 //等待场中断
#define WAITHREF 3 //等待行中断
#pragma CODE_SEG DEFAULT //后续代码置于默认区域内
int zhidao=450 ;
int wandao= 450 ;
int SteerE0=0;
int SteerE1=0;
int M_flag=1;
int P_flag=0;
/****************************************18,118,118,118,
118,118,118,118,118,118};
///////////////////////LED////////////////////////
//////////////////////////////////////////////////
unsigned char Led[] = {0xFB,0xF7,0xDF,0xBF}; //PE2.3.5.6口显示,0对应的LED灯亮
//通用IO口初始化//
飞思卡尔智能车IO 口说明2
1内存映射。
632.3.2注册说明。
712.3.3端口A数据寄存器(PORTA)。
732.3.4端口B数据寄存器(PORTB )。
732.3.5端口A数据方向寄存器(DDRA)。
742.3.6端口B数据方向寄存器(DDRB)。
742.3.7PIM信息注册。
752.3.8端口E数据寄存器(PORTE)。
752.3.9端口E数据方向寄存器(DDRE)。
762.3.10端口ABEK,BKGD引脚上拉控制寄存器(PUCR)。
77 2.3.11端口ABEK降低驱动器寄存器(RDRIV)。
782.3.12 ECLK控制寄存器(ECLKCTL)。
792.3.13PIM信息注册。
802.3.14IRQ控制寄存器(IRQCR)。
812.3.15PIM信息保留注册PIMTEST。
812.3.16端口k数据寄存器(PORTK)。
822.3.17端口k数据方向寄存器(DDRK)。
822.3.18端口T数据寄存器(总站)。
832.3.19端口科技投入注册(PTIT)。
842.3.20端口T数据方向寄存器(DDRT)。
852.3.21端口.降低驱动器寄存器(RDRT)。
852.3.22端口.拉设备使能寄存器(PERT)。
862.3.23端口.极性选择寄存器(PPST)。
862.3.24保留PIM信息注册。
872.3.25端口.路由注册(PTTRR)。
872.3.26端口S数据寄存器(PTS)。
892.3.27端口S输入寄存器(PTIS)。
902.3.28端口S数据方向寄存器(DDRS)。
91 2.3.29端口S降低驱动器寄存器(RDRS)。
92 2.3.30端口S拉设备使能寄存器(PERS)。
92 2.3.31端口S极性选择寄存器(PPSS)。
932.3.32端口S线或模式寄存器(WOMS)。
93 2.3.33保留PIM信息注册。
942.3.34端口M数据注册系统(PTM)。
942.3.35端口M输入寄存器(PTIM)。
962.3.36端口M数据方向寄存器(DDRM)。
飞思卡尔 I.MX6Q-vpu视频编解码
飞思卡尔 I.MX6Q-vpu视频编解码前言对应使用飞思卡尔的vpu进行硬件编解码,你需要配置出你linux 下LTIB环境,导出imx-test中的mxc_vpu_test源码,这方面的内容在之前文档已经说明,可以去查看,这篇文章主要介绍视频采集以及编解码,对于摄像头设备主要有两种,一种是USB摄像头,另一种是摄像头模组,例如:ov5640;本文主要分析这两种视频采集后再编解码。
1、摄像头模组ov5640视频采集编解码如果你是买着天嵌的开发板,那么这方面的驱动都已经有了,如果你是自己编译的内核或者没这个驱动,那么你需要手动去加载,下面这些都需要去加载:insmod ipu_prp_enc.koinsmod ipu_bg_overlay_sdc.koinsmod ipu_fg_overlay_sdc.koinsmod ipu_csi_enc.koinsmod ov5642_camera.koinsmod mxc_v4l2_capture.ko加载完成后,就可以直接用mxc_vpu_test编译出来的mxc_vpu_test.out去进行编解码:./mxc_vpu_test.out -E "-o vpu.h264 -f 2 -w 640 -h 480"//摄像头采集后编码./mxc_vpu_test.out -D "-i vpu.h264 -f 2 -u 1 -w 640 -h 480"//解码对于mxc_vpu_test.out更多的功能,你可以使用mxc_vpu_test.out -help去查看,或者直接去看源码。
2、USB摄像头视频采集编解码对于usb摄像头,只要你的ARM板支持usb摄像头,就会在/dev/下产生设备video*,这就是usb摄像头设备,你可以直接对它操作,对于usb摄像头难的不是驱动,而是飞思卡尔官方代码mxc_vpu_test是不支持usb摄像头的,所以你需要去修改源码来实现对usb摄像头的支持,对于代码的修改,主要有两点:修改v4l2代码适合usb摄像头、把摄像头采集的数据YUV422转为420(NV12)。
智能车摄像头DMA采集方案
在之前做飞思卡尔智能车比赛时接触过K60的DMA,用DMA可以采集图像,也可以用DMA来测速。
概念相信大家都清楚:所谓 DMA就是直接内存取( Direct Memory Access ),是计算机科学中的一种内存访问技术。
书上说,DMA模块可以不占用CPU自行传输数据,能够减轻CPU的负担,然而具体原理是怎样的呢?为什么DMA能够不需要CPU的介入呢?我查阅了相关资料,大概地了解了些。
在STM32中,DMA单元和Cortex CPU之间对总线使用一种交叉存取的机制。
DMA 传输遵循相应的传输流程。
其中,在数据从内存传输到内存的情况下,每传输一个字要消耗5个时钟周期:1个读周期,1个写周期,插入3个空闲周期供CPU使用。
所以,每个DMA通道都只是在总线存取周期才会占用总线,即使传输大量数据,DMA单元最大也只会消耗40%的数据总线带宽。
所以说,STM32中的DMA与CPU对总线的使用方式是交叉式的。
在K60中,DMA是通过DMA控制器接管接管数据和地址总线。
如果CPU正在执行指令,DMA控制利用空闲的地址和数据总线完成数据传送,某种程度上说,CPU 运算和数据传送是在并行进行的。
K60的DMA数据的传送分为主循环(major loop)和副循环(minor loop)。
major loop循环一次,可能需要minor loop循环多次。
每个minor loop循环都需要DMA源发来请求或者通过软件请求。
每个minor loop传送完毕,对应的DMA通道就进入空闲模式,等待下一次DMA请求。
当所有DMA传送完毕,即置DONE标志,并且可以通过设置选择传送完毕是否触发中断。
此外,可以通过相关寄存器设置,使用Kinetis的DMA模块的主/副循环链接功能、散/聚模式、副循环映射。
对DMA模块的相应的寄存器进行初始化后,便可开启DMA功能。
例如(K60例程):以智能车摄像头组图采集应用为例。
使GPIO口 D0~D7采集数字摄像头OV7620的8位灰度输出,使用引脚位灰度输出,使用引脚 A19输入像素同步脉冲pclk4分频后的信号,上升沿触发分频后的信号,上升沿触发DMA 请求。
飞思卡尔智能车 XS128 PE编程入门教程
飞思卡尔智能车XS128 PE编程入门教程(1)首先打开CodeWarrior 5.0 开发环境。
然后在弹出的选项中选择新建工程注释(如果没有弹出这个对话框的,可以在下面的File中选择New Project新建一个工程)(2) 选择开发芯片的型号(这里我们使用的是MC9S12XS128)接着选择TBDML这个是我们使用在线调试功能的选项。
(3) 选择工程的生成路径,注意:如果我们不使用PE编程功能的话,在这步结束后,我们可以直接选择完成按钮来完成工程的新建。
(4) (PE编程功能的步骤)下一步,这个对话框我们什么都不用选择,直接点击下一步。
(5)选择下面这个选项来启动PE编程功能。
(6) 红色边框中的选项的功能为是否启动浮点数据的使用,默认第一个是不启用,第二个是启用,float数据为32位。
double为32位,第三个是启用,float 数据为32位,double数据为64位。
(7)最后一步什么都不要设置,直接点击完成。
(8) 以上步骤我们完成了一个XS128工程的新建步骤。
PE的使用步骤:(1) 新建工程后,会自动弹出个芯片封装型号的选择,选择好后点击OK。
(注意:我们学校有些芯片是80管脚的,也有112管脚的,所以注意选择红线标注的选项)(2) 点击OK后,就会出现我们要编程的环境了。
如下(3)红色标注的地方就是我们该工程的工作区了。
细心的同学就会发现,它生成的文件中没有我们需要写的源文件XXX.c 。
那我们现在就来生成这些文件。
找到下图的按键Processor Expert。
然后点击第二个选项的Generate Code ' XXXX .mcp' (这里的XXXX表示该工程名称).下面是自动生成的文件。
这时候我们发现软件为我们自动的生成了一个Project.c(Project 是我这个工程建立的文件命,不同的工程文件名将导致这个名字不同)的文件。
这个就是我们将要编写的源文件了,它里面包含了我们的主函数main()。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
**************************************************************************/
void SystemInit(void)
{ AbsoluteTime = 0; // 初始化系统时钟
DDRB = 0xff; // 初始化PORTB,用于数据输出
}
else
{
ie+=e;
speed_0=speed_0-(Kp*e/10)-(int)(Ki*ie/1000)+Kd*(e-e_1);
SetSpeed();
}
}
void SetSpeed(void)
{ if(speed_0>2400)
speed_0=2400;
int e=0,e_1=0;
int ie=0;
int Kp=35;
int Kd=0;
int Ki=10;//5;
int PACN0_i;
int SpeedMin=90,SpeedMax=400;
char a;
/***********************************************************************
PWMCNT23 = 0xFF;
PWMCNT45 = 0xFF;
PWMCNT67 = 0xFF;
PWMPER01 = 60000; // 驱动前轮舵机,周期20ms,频率50Hz
PWMPER23 = 2400; //周期0.1ms,频率10kHz
PWMPER67 = 2400;
PBCTL_PBEN=1;//16位累加器B使能
TC4 = TC4; // 清除中断标志位
TC5 = TC5;
TC6 = TC6;
CCDInit();
}
**********************************
函数名称:CCDInit
功能描述:图像空间初始化
interrupt void Real_Time_Interrupt(void)
{
AbsoluteTime++; // 运行系统时钟
SpeedPID();
PORTB=(char)(PACN10);
CRGFLG = 0x80; // 清中断标志
EnableInterrupts;
PID数据
***********************************************************************/
static int CurrentSpeed=0,DstSpeed=90;
static int waittime=0;
int speed_0=0;
FieldCNT = 0; // 场计数器初始化
ETCInit();
PWMInit();
RTIInit();
}
static void RTIInit(void) {
/* setup of the RTI interrupt frequency */
/* adjusted to get 1 millisecond (10.24 ms) with 16 MHz oscillator */
}
/*******************************************************************/
void SpeedPID(void)
{
PACN0_i=PACN10;
CurrentSpeed = PACN0_i;//码盘输入引脚PT0
路径记忆数据
************************************************************************/
int length=0;
int bendstraightMemory[100];//直道弯道数据存储
/*********************************************************************
// 设置占空比初始值
PWMDTY01 = 4200//舵机要求PWM高电平宽度0.5ms~2.5ms对应计数器数值为3800~4450~5150右
PWMDTY23 =1660;
PWMDTY67 =0;
PWME = 0xFF; // 所有PWM通道使能
}
EnableInterrupts;
for(;;) {
EnableInterrupts;
JourneyMemory();
PictureDispose();
}
}
/************************************************************************
void SpeedPID(voidห้องสมุดไป่ตู้;
static void RTIInit(void);
void SetSpeed(void);
/***********************************************************************
路径记忆函数
************************************************************************/
PACN10=0;
e_1=e;
e=CurrentSpeed-DstSpeed;//-CurrentSpeed;
if(e<-20){
PWMDTY67 =0;
PWMDTY23 =2400;
}
else if(e>20){
PWMDTY23=0;
PWMDTY67=2400;
TIOS_IOS4 = 0; // 视频输入捕获
TIOS_IOS5 = 0; // 行同步
TIOS_IOS6 = 0; // 场同步
TSCR1_TEN = 1; // 使能计数
TSCR1_TFFCA = 1; // 捕获中断、比较中断标志位通过读取数据和写入数据清除
PACTL=0x40; //16位累加器A使能 ,下降沿工作
PWMPRCLK = 0x03; // bus clock:24M;Clock A--8分频,Clock B--0分频
PWMCAE = 0x00; // 所有的PWM输出为左对齐方式输出
PWMCTL = 0xFF; // 将两个8位的PWM输出通道组合成一个16位的PWM输出通
PWMCNT01 = 0xFF; // PWM计数器清零
int PictureCoordinate[10]={0,0,0,0,0,0,0,0,0,0};//图像坐标
unsigned int FieldCNT;
int RowCNT;
int CapFlag;
long coordinate1,coordinate2,line_wideth;
int se = 0;
摄像头函数
*********************************************************************/
void ETCInit(void);
void CCDInit(void);
void PWMInit(void);
void SystemInit(void);
********************************
void PWMInit(void) {
PWME = 0x00; // 禁止所有的PWM输出通道
PWMPOL = 0xFF; // 所有的PWM输出高电平有效
PWMCLK = 0x00; // Clock A && Clock B is the clock source for PWM channel 0~7
unsigned int Picture1[10][4]={{600,600,0,40},{600,600,0,60},{600,600,0,80},
{600,600,0,100},{600,600,0,120},{600,600,0,140},
{600,600,0,160},{600,600,0,180},{600,600,0,200},
{600,600,0,220}};
unsigned int Picturewrflag[10]; //图像数据真伪判别标志
TCTL3_EDG7B=1;
TCTL3_EDG7A=0; //7 channel Capture on falling edges only
TIOS_IOS0=0; //0 channel input compare
TIOS_IOS7=0; //7 channel input compare
EnableInterrupts;
}
/**************************************************************************
速度PID控制区域
***************************************************************************
#include <hidef.h> /* common defines and macros */