《鸿蒙智能互联设备开发(微课版)》 课件 第8章 智能出行设备开发_第1页
《鸿蒙智能互联设备开发(微课版)》 课件 第8章 智能出行设备开发_第2页
《鸿蒙智能互联设备开发(微课版)》 课件 第8章 智能出行设备开发_第3页
《鸿蒙智能互联设备开发(微课版)》 课件 第8章 智能出行设备开发_第4页
《鸿蒙智能互联设备开发(微课版)》 课件 第8章 智能出行设备开发_第5页
已阅读5页,还剩65页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

8.1.1智能出行设备硬件环境介绍通过本节学习,您可以:了解智能出行设备硬件环境介绍智能出行设备硬件环境介绍1.STM32MP157芯片STM32MP157A芯片是由意法半导体公司推出的一款嵌入式处理器,该处理器采用双核Cortex-A7架构和Cortex-M4内核,支持多种接口和协议,可广泛应用于工业控制、智能家居、智能物联网等领域。

STM32MP157A芯片特性:拥有丰富的硬件资源,包括GPIO、SPI、I2C、UART、USB等接口。支持多种存储介质和通信协议,如NANDFlash、SD卡、Ethernet、WiFi、Bluetooth等。支持多种外设,如ADC、DAC、PWM、CAN、RTC等。智能出行设备硬件环境介绍2.GPS模块L80-R是一款超紧凑型GPS模块,适合微型设备。L80-R模块集成了贴片天线,支持自辅助AGPS轨道预测技术。AGPS技术使L80-R能自动计算和预测长达三天的轨道信息,并将这些信息存储到内部RAM存储器中。

GPS模块适合用于车载、个人跟踪、工业级PDA以及相关手持设备等领域,特别适合于GPS接收机。

智能出行设备硬件环境介绍3.直流电机测速电机采用直流减速电机,电动机转轴带动轴上的磁钢旋转,从而改变磁场大小,通过霍尔电路将磁场变化转换为脉冲信号,经放大整形,输出矩形脉冲信号。当转速改变时,输出脉冲的频率会发生变化。从而获得减速电机旋转的速度。电机拥有两个霍尔传感器,可用于检测电机的转动速度和转动方向,通过改变PWM占空比的方式控制转动的速度。

智能出行设备硬件环境介绍4.蜂鸣器蜂鸣器是一种一体化结构的电子器件,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、电子设备、电话机、定时器等电子产品中作发声器件。

5.LED灯贴片LED又称SMDLED,是电路板上常用的元器件。改变高低电平可控制LED灯的亮灭。

谢谢8.1.2PWM控制技术通过本节学习,您可以:了解PWM控制技术PWM控制技术PWM(PulseWidthModulation)控制技术是对脉冲的宽度进行调制的技术,即通过对一系列脉冲的宽度进行调制,来等效的获得所需要的波形。PWM控制技术中有两个参数:频率:频率即周期的倒数1/T。占空比:占空比是高电平在一个周期内所占的比例T1/(T1+T2)。PWM控制技术通过改变单位时间内脉冲的个数就可以实现调频。通过改变占空比就可以实现调压。占空比越大,得到的平均电压也就越大;占空比越小,得到的平均电压就越小。改变频率改变占空比谢谢8.2.1搭建智能出行设备开发代码工程通过本节学习,您可以:了解智能出行设备开发代码工程的搭建方法搭建智能出行设备开发代码工程在stm32mp157应用层工程目录下创建文件夹qc,在qc文件夹下创建qc_app.c与BUILD.gn文件。在stm32mp157驱动层工程目录的module_driver文件夹下创建文件夹QC。在QC文件夹下创建QC_hdf.c文件以及inc与src文件夹。在inc文件夹下创建QC.h与pid.h文件。在src文件夹下创建QC.c与pid.c文件。应用层工程文件位置驱动层工程文件位置谢谢8.2.2LED指示灯驱动开发通过本节学习,您可以:了解LED指示灯的驱动开发LED指示灯驱动开发1.初始化GPIO引脚宏定义PI8引脚。连接LED指示灯的引脚为PI8,PI8引脚为136号引脚,在库函数BM_Module_GPIO.c将该引脚定义为MODULE_IO_15。所以只需要对MODULE_IO_15进行宏定义即可。初始化PI8引脚。调用库函数BM_Module_GPIO.c中的“MODULE_GPIOInit()”函数即可对引脚初始化。将引脚配置为禁止上下拉模式。

caseMODULE_IO_15://PI8

return136;

...

#defineQC_LightMODULE_IO_15//宏定义LED指示灯引脚

MODULE_GPIOInit(QC_Light,MODULE_GPIO_Out_PullNone);//初始化补光灯引脚LED指示灯驱动开发2.设置蜂鸣器状态调用库函数BM_Module_GPIO.c中的“MODULE_GPIOWrite()”函数即可实现对LED指示灯的控制。因为LED指示灯另一端接的是3.3V电源,所以当PI8脚输出低电平时LED指示灯点亮,当PI8脚输出高电平时LED指示灯熄灭。

intQC_Light_StatusSet(QC_Status_ENUMstatus)

{

intret=0;

if(status==ON)

ret=MODULE_GPIOWrite(QC_Light,0);//设置输出低电平点亮灯

if(status==OFF)

ret=MODULE_GPIOWrite(QC_Light,1);//设置输出高电平关闭灯

returnret;}谢谢8.2.3蜂鸣器驱动开发通过本节学习,您可以:了解蜂鸣器的驱动开发方法蜂鸣器驱动开发1.初始化GPIO引脚宏定义PB12引脚。连接蜂鸣器的引脚为PB12,PB12引脚为28号引脚,在库函数BM_Module_GPIO.c将该引脚定义为MODULE_IO_9,所以只需要对MODULE_IO_9进行宏定义即可。初始化PB12引脚。调用库函数BM_Module_GPIO.c中的“MODULE_GPIOInit()”函数即可对引脚初始化。将引脚配置为禁止上下拉模式。caseMODULE_IO_9://PB12

return28;...#defineQC_BeepMODULE_IO_9//蜂鸣器的引脚MODULE_GPIOInit(QC_Beep,MODULE_GPIO_Out_PullNone);//初始化蜂鸣器蜂鸣器驱动开发2.设置蜂鸣器状态调用库函数BM_Module_GPIO.c中的“MODULE_GPIOWrite()”函数即可实现对蜂鸣器的控制。当PB12脚输出高电平时蜂鸣器打开,当PB12脚输出低电平时蜂鸣器关闭。

intQC_Beep_StatusSet(QC_Status_ENUMstatus)

{

intret=0;

if(status==ON)

ret=MODULE_GPIOWrite(QC_Beep,1);//设置输出高电平打开蜂鸣器

if(status==OFF)

ret=MODULE_GPIOWrite(QC_Beep,0);//设置输出低电平关闭蜂鸣器

returnret;

}谢谢8.2.4GPS驱动开发通过本节学习,您可以:了解PGS模块的驱动开发GPS驱动开发GPS模块需要先通过启动引脚来启动模块,启动后GPS模块会采集定位信息并通过串口发送给stm32f103,stm32f103采集到定位信息后进行解析,再与速度信息一起通过IIC接口发送给stm32mp157。1.启动GPS模块(1)GPS模块通过stm32mp157的PE8引脚输出高电平启动。宏定义PE8引脚。PE8引脚为72号引脚,在库函数BM_Module_GPIO.c将该引脚定义为MODULE_IO_12,所以只需要对MODULE_IO_12进行宏定义即可。caseMODULE_IO_12://PE8

return72;

...#defineQC_StartMODULE_IO_12//宏定义启动GPS引脚初始化PE8引脚。调用库函数BM_Module_GPIO.c中的“MODULE_GPIOInit()”函数即可对引脚初始化。将引脚配置为上拉输出模式。MODULE_GPIOInit(QC_Start,MODULE_GPIO_Out_PullUp);//初始化启动GPS引脚GPS驱动开发1.启动GPS模块(2)启动GPS模块。调用库函数BM_Module_GPIO.c中的“MODULE_GPIOWrite()”函数使PE8脚输出高电平时启动GPS模块。

voidQC_Init(void)

{

MODULE_GPIOInit(QC_Beep,MODULE_GPIO_Out_PullNone);//初始化蜂鸣器

MODULE_GPIOInit(QC_Light,MODULE_GPIO_Out_PullNone);//初始化补光灯引脚

MODULE_GPIOInit(QC_Start,MODULE_GPIO_Out_PullUp);//初始化启动GPS引脚

MODULE_GPIOWrite(QC_Start,1);//设置输出高电平启动GPS

}GPS驱动开发2.获取GPS模块定位信息GPS模块采集到数据后通过IIC1发送给stm32mp157,stm32mp157截取GPS模块采集的GPRMC格式数据,对此格式数据进行解析就可以得到经纬度信息。(1)获取GPS数据。通过IIC1获取到数据,再通过解析函数解析经纬度信息。

voidQC_gps(void)

{

uint8_tRead_Buff_gps[100]={0};

...

MODULE_IICRead(0xA2,Read_Buff_gps,90);//读取数据

NMEA_BDS_GPRMC_Analysis(&gpsmsg,Read_Buff_gps);//解析数据

...

}GPS驱动开发2.获取GPS模块定位信息(2)经纬度解析函数。解析GPRMC格式数据,提取数据中的经纬度信息。GPRMC格式数据例如:$GPRMC,090634.000,A,2812.7182,N,11252.7955,E,0.23,29.82,270421,,,A*5A需要解析的纬度数据为第三个逗号到第四个逗号的数据2812.7182,小数点前两位为分,两位前的为度。解析出来为28度12分。需要解析的经度数据为第五个逗号到第六个逗号的数据为11252.7955,小数点前两位为分,两位前的为度。解析出来为112度52分。GPS驱动开发GPRMC格式数据解析。先通过“strstr()”函数在GPS模块回传的数据中找出GPRMC格式数据的首地址,如上例为“$”的地址。根据“NMEA_Comma_Pos()”函数得出GPRMC格式数据到第三个逗号的长度,纬度为数据“$GPRMC,090634.000,”的长度20,经度数据“$GPRMC,090634.000,A,2812.7182,N,”的长度32。数据计算:GPRMC格式数据的首地址(“$”的地址)加上此长度(20)就是纬度数据的地址(“2812.7182”中第一个“2”的地址),通过“NMEA_Pow()”函数将纬度数据转换成整型得到“2812”,最后将纬度数据除100得到纬度数据“28.12”,代表纬度为28度12分。经度计算只有加上长度为32不一样,其余原理一样。GPS驱动开发

voidNMEA_BDS_GPRMC_Analysis(gps_msg*gpsmsg,u8*buf)

{

u8*p4,dx;

u8posx;

u32temp;

p4=(u8*)strstr((const

char*)buf,"$GPRMC");//判断$GPRMC首地址.

if(p4!=NULL){

posx=NMEA_Comma_Pos(p4,L80R_CONSTANT_3);//得到纬度

if(posx!=0XFF){

temp=NMEA_Str2num(p4+posx,&dx);

gpsmsg->latitude_bd=temp;

}

posx=NMEA_Comma_Pos(p4,L80R_CONSTANT_5);//得到经度

if(posx!=0XFF){

temp=NMEA_Str2num(p4+posx,&dx);GPS驱动开发

gpsmsg->longitude_bd=temp;

}

}

memset(buf,0,sizeof(buf));

}

voidQC_gps(void)

{

...

NMEA_BDS_GPRMC_Analysis(&gpsmsg,Read_Buff_gps);//解析数据

Longitude=(float)((float)gpsmsg.longitude_bd/L80R_DATA_LEN);

Latitude=(float)((float)gpsmsg.latitude_bd/L80R_DATA_LEN);

printf("\r\nLongitude:%f\r\n",Longitude);

printf("\r\nLatitude:%f\r\n",Latitude);

}GPS驱动开发数据提取与转换。先用循环一个一个字符判断是否为“.”,并记录有多少个字符。当字符为“.”时跳出循环。以纬度数据提取为例:输入为“2812.7182”的第一个“2”的地址,先进入循环判断“2”是不是“.”,不是地址加1数据长度也加1,进入下个循环直到“.”退出,此时为“2812”的长度4。再将数据一个一个字符转换为整数并通过幂函数“NMEA_Pow()”乘相应的位数得到整型的“2812”纬度数据。GPS驱动开发

intNMEA_Str2num(u8*buf,u8*dx)

{

u8*p=buf;

u32ires=0;

u8ilen=0,i;

u8mask=0;

intres;

while(1)

{

if(*p=='-'){

mask|=0x02;

p++;

}//说明有负数

if(*p==','||*p=='*'){

break;//遇到结束符

}

if(*p=='.'){//遇到小数点

break;GPS驱动开发

}else

if(*p>'9'||(*p<'0')){//数字不在0和9之内,说明有非法字符

ilen=0;

break;

}

ilen++;//str长度加一

p++;//下一个字符

}

if(mask&0x02){

buf++;//移到下一位,除去负号

}

for(i=0;i<ilen;i++){//得到整数部分数据

ires+=NMEA_Pow(L80R_CONSTANT_10,ilen-1-i)*(buf[i]-'0');

}

res=ires;

if(mask&0x02)

res=-res;

returnres;

}GPS驱动开发编写幂函数。计算n个m相乘,主要用来将单个整型数据赋予位数。

u32NMEA_Pow(u8m,u8n)

{

u32result=1;

while(n--){

result*=m;

}

returnresult;}GPS驱动开发从字符串里面得到第几个逗号所在的位置。通过循环每次都判断字符是否为“,”,每次循环地址加1。当循环到“,”时第几个逗号就减1,当减到0时代表地址已经到第几个逗号所在的位置跳出循环。再将字符串的首地址减去此时位置的地址就可以得到第几个逗号前所有字符的数量。

u8NMEA_Comma_Pos(u8*buf,u8cx)

{

u8*p=buf;

while(cx){

if(*buf=='*'||*buf<''||*buf>'z'){

return0xFF;

}

if(*buf==','){

cx--;

}

buf++;

}

returnbuf-p;

}谢谢8.2.5测速编码器驱动开发通过本节学习,您可以:了解测速编码器的驱动开发测速编码器驱动开发测速编码器模块采集到速度数据后通过IIC1发送给stm32mp157。1.stm32mp157的IIC通讯stm32mp157的IIC通讯用到的是第一组IIC——IIC1。库函数Module_Common文件中已经做出了打开IIC1“MODULE_IICOpen()”及读取IIC1“MODULE_IICRead()”函数的定义,所以只需调用该函数就行。

#defineBM_MODULE_IIC_CHANNEL_NUM1

...

MODULE_StatusMODULE_IICOpen()

{

if(i2cHandler!=NULL){

MODULE_Log("I2Chasopened,pleasedon'topenagain!");

returnMODULE_Failed;

}测速编码器驱动开发

i2cHandler=I2cOpen(BM_MODULE_IIC_CHANNEL_NUM);//打开IIC1

if(i2cHandler==NULL){

MODULE_Log("I2Copenfailed!");

returnMODULE_Failed;

}

returnMODULE_Ok;

}

MODULE_StatusMODULE_IICRead(uint32_taddr,uint8_t*data,uint32_tlen)

{测速编码器驱动开发

MODULE_IIC_Msgmsg;

msg.addr=addr;

msg.buf=data;

msg.len=len;

msg.flags=MODULE_I2C_FLAG_READ;

if(MODULE_IICTransmit(&msg,1)!=MODULE_Ok){

HDF_LOGE("i2creaderr");

printf("i2creaderr");

return-1;

}

return0;

}测速编码器驱动开发2.获取速度通过IIC1获取速度数据后,对数据速度进行解析。因为速度数据为字符串,所以需要将字符串转换为整型数据,将对应的字符数据减去字符“0”就可以得到该字符对应的整型。

intQC_speed(void)

{

intret=0;

uint8_tRead_Buff_speed[5]={0};

MODULE_IICRead(0xA2,Read_Buff_speed,2);//读取数据

if((Read_Buff_speed[0]-'0')==0)

{

ret=Read_Buff_speed[1]-'0';

}

测速编码器驱动开发

else

{

ret=Read_Buff_speed[0]-'0';

ret=ret*10+Read_Buff_speed[1]-'0';

}

if((ret>100)||(ret<0))

{

ret=-1;

}

returnret;}谢谢8.2.6直流电机驱动开发通过本节学习,您可以:了解直流电机的驱动开发直流电机驱动开发stm32mp157通过控制PWM波的占空比来控制电机的转速。1.宏定义PWM索引、分频系数、频率及占空比通过输出PWM波就可以控制电机的转速。控制电机的引脚为PA6,使用PA6脚的TIM3_CH1输出PWM波。在pwm_config.hcs文件中定义了PA6引脚,TIM3_CH1及PWM索引号。

device_pwm3::pwm_device{

tim_addr=0x40001000;

tim_clk_hz=10000000;//10KHZ

channel=1;//channel_1

num=3;//PWM索引号

gpio_port_addr=0x50002000;//GPIOA

pin_number=6;//PA6

match_attr="st_stm32mp157_pwm_3";}直流电机驱动开发宏定义PWM索引号、分频系数、频率及占空比。

#defineMOTOR_PWM13//PWM索引

#defineMOTOR_PWM1_POLARITY0//分频系数

#defineMOTOR_PWM1_PERIOD1000//频率

#defineMOTOR_PWM1_DUTY0//占空比直流电机驱动开发2.电机初始化Module_Common文件中已经做出使用PWM相关函数的定义,所以只需调用这些函数就行。设置PWM的输出频率及占空比。通过“MODULE_PWMSet()”函数实现。

voidEncoder_Motor_PWMSet(uint32_tperiod,uint32_tduty)

{

MODULE_PWMSet(period,duty);

MODULE_Log("Encoder_MotorPWMSet.");

}停止输出PWM波。通过“MODULE_PWMStop()”函数实现。

voidEncoder_Motor_Stop(void)

{

MODULE_PWMStop();//停止输出PWM

MODULE_Log("Encoder_MotorStop.");

}直流电机驱动开发初始化PWM。先用“MODULE_PWMOpen()”函数根据PWM索引打开引脚的PWM功能,然后用“MODULE_PWMSetPolarity()”函数设置分频系数,接着设置PWM的输出频率及占空比,最后停止输出PWM波等需要用到的时候再开启。

voidEncoder_Motor_Init(void)

{

MODULE_PWMOpen(MOTOR_PWM1);//打开PWM

MODULE_PWMSetPolarity(MOTOR_PWM1_POLARITY);//设置分频系数

Encoder_Motor_PWMSet(MOTOR_PWM1_PERIOD,MOTOR_PWM1_DUTY);//设置PWM输出参数

Encoder_Motor_Stop();//停止输出PWM

MODULE_Log("Encoder_Motor_Initsucceed.");

}直流电机驱动开发3.设置PWM的占空比因为占空比的精度为0.1%,所以需要将输入的占空比乘十才能得到实际的速度,使用“MODULE_PWMSetDuty()”函数写入占空比。

int32_tEncoder_Motor_PWMSetDuty(uint32_tduty)

{

if((duty<1)||(duty>100))

{

MODULE_Log("DutyParameterSetupError!");

return-1;

}

MODULE_PWMSetDuty(duty*10);

MODULE_Log("Encoder_MotorPWMDutySetupSuccess.");

return0;

}直流电机驱动开发4.输出PWM波输出PWM波是通过“MODULE_PWMStart()”函数来实现的。

voidEncoder_Motor_Start(void)

{

MODULE_PWMStart();//开始输出PWM

MODULE_Log("Encoder_MotorStart.");

}谢谢8.2.7PID调速功能开发通过本节学习,您可以:了解PID调速功能的开发PID调速功能开发由于机械结构、阻力等诸多问题会导致实际的电机转速与预设的电机转速存在一定的误差值,要想消除该误差值就需要用到PID控制算法。PID控制算法是结合比例、积分和微分三种环节于一体的自动控制算法,它是连续系统中技术最为成熟,应用最为广泛的一种控制算法。PID控制组件的实质就是根据输入的偏差值,按照比例、积分、微分的函数关系进行运算,再将运算的结果控制输出,从而达到电机的实际转速与预设的转速相等。PID调速功能开发PID控制算法中比例、积分和微分的各自作用如下:比例算法:通过计算出电机实际转速与预设值的误差值,乘以对应的比例系数,再加上前一次PID计算的输出值即可使得实际转速趋近于预设值。积分算法:通过计算前五次误差的和再乘以对应的积分系数,再加上前一次PID计算的输出值即可使得实际转速等于预设值。微分算法:通过计算本次误差与上次误差的差值再乘以对应的微分系数,再加上前一次PID计算的输出值即可防止转速波动过大,能够平稳的使实际转速到达预设转速。PID调速功能开发(1)对PID结构体进行定义。定义PID算法所需要用到的变量及数组。

typedef

struct

{

pid_ykp;//比例参数

pid_yki;//积分参数

pid_ykd;//差分参数

pid_yinput;//输入值

pid_yset_point;//设定的期望值

pid_youtput;//计算得出的值

pid_youtput_speed;//实际输出的值

pid_yLast_output;//上次实际输出的值

pid_ypid_output;//PID计算值

pid_yerror;//误差值

pid_yLast_error;//上次误差值

interror_data;//误差值次数

pid_yerror_i[5];//前五次误差值

pid_yintegral;//内部的积分值

pid_ydifferential;//内部的微分值

pid_yproportion;//内部的比例值

}pid_struct;PID调速功能开发(2)对PID参数初始化。对比例、积分、微分系数赋值,上次误差值、误差值次数与前误差的误差值均赋0,初始输出给电机的转速为20。

voidpid_init(pid_struct*pid)

{

pid->kp=0.5;//比例系数

pid->ki=0.02;//积分系数

pid->kd=0.05;//微分系数

pid->Last_error=0;//上次误差值

pid->Last_output=20;//初始输出给电机的转速

pid->error_data=0;//误差值次数

/**前五次误差值**/

for(intj=0;j<5;j++)

{

pid->error_i[j]=0;

}}PID调速功能开发(3)PID算法综合了比例算法、积分算法和微分算法这三种算法。比例算法:将采集到的实际速度与预设的目标速度相减得到误差值,再乘以比例系数得到比例值。积分算法:计算前五次误差的和再乘以对应的积分系数得到积分值。pid->error=pid->set_point-pid->input;//误差

pid->proportion=pid->kp*pid->error;//比例计算

/**积分算法**/

pid->error_i[pid->error_data]=pid->error;//记录5次误差用于积分计算

for(intj=0;j<5;j++)

{

pid->integral+=pid->error_i[j];/*误差积累*/

}

pid->integral=pid->integral*pid->ki;//积分计算

pid->error_data++;//数组地址加一,方便下次误差存入

/**更新数组地址**/

if(pid->error_data==5)

{

pid->error_data=0;}PID调速功能开发微分算法:将本次的误差值减去上次的误差值得到差值,再乘以微分系数得到微分值。pid->differential=pid->kd*(pid->error-pid->Last_error);//微分计算PID运算:将比

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论