中学组一等奖作品
{
while (*p != '\\0') {
commandText[commandTextPointer++] = *(p++); } }
4.2. 救援车控制程序
救援车需要完成的功能是:接收GPS模块发出的定位数据,从$GPRMC语句从提取自身的经纬度信息,存储在单片机(MC9S12XS128MAL)内;向上位机发送自身位置信息;接收上位机的控制指令,提取目标位置;动态调整直流电机与舵机的控制PWM波的占空比,完成对救援车速度和转向的控制。
以上功能所涉及的软件功能有: 1.总线频率设置(PLL模块); 2.串口数据收发(SCI模块);
3.从$GPRMC语句中提取经纬度信息; 4.控制指令分析。
5. PWM设置(PWM模块)。
前三部分已经在之前进行了介绍,下面仅对最后两部分作详细解释。 4.2.1. 控制指令分析
这一部分主要是对接收到上位机的指令进行分析,并分情况进行响应。具体处理过程为:
void Make_Desicion_Kart_Control() {
if (globalCount <= delayStart) { return ; } else {
switch (pcMessage[1]) { case 'A':
automaticControl = 1; manualControl = 0; break; case 'L':
targetLatitude = StringToFloat(&(pcMessage[5])); targetLongitude = StringToFloat(&(pcMessage[20])); targetPositionObtained = 1; break; case 'M':
automaticControl = 0; manualControl = 1; break;
41
第二届“北斗杯”全国青少年科技创新大赛优秀作品
case 'S':
speed = pcMessage[3];
steering = pcMessage[6];
PWMDTY45 = (uint16) ((100 - steering) * (PWMDTY45_Right - PWMDTY45_Left) / 100 + PWMDTY45_Left);
PWMDTY67 = (uint16) (speed * (PWMDTY67_StandardMax - PWMDTY67_StandardMin) / 100 + PWMDTY67_StandardMin);
break; default: break; } } }
4.2.2. PWM设置 (PWM模块)
MC9S12XS128MAL单片机的PWM模块提供了8个输出通道,每一个输出通道既可以独立地进行输出,也可以进行两两级联进行输出。每一个输出通道都有一个精确的计数器(计算脉冲的个数),一个周期控制寄存器和两个可供选择的时钟源(PWM0、PWM1、PWM4、PWM5可以选择A或SA时钟,PWM2、PWM3、PWM6、PWM7可以选择B或SB时钟)。
时钟的分频可通过对PWMPRCLK寄存器和PWMSCLAx寄存器进行设置得以实现。对PWMPERx寄存器和PWMxDTYx寄存器,可以分别对PWM波的周期和占空比进行调整。具体设置过程为:
void PWM_Init() {
//steering PWM control PWME_PWME4 = 0;
PWME_PWME5 = 0; //disable all outputs PWMCLK_PCLK4 = 1; //SA PWMCLK_PCLK5 = 1; //SA PWMCTL_CON45 = 1; PWMSCLA = 20;
PWMPER45 = 4000; //45: 100Hz
PWMDTY45 = PWMDTY45_Middle; //45: 15% PWMPOL_PPOL5 = 1; PWMCAE_CAE5 = 0; PWMCNT4 = 0; PWMCNT5 = 0; PWME_PWME4 = 1; PWME_PWME5 = 1;
//speed PWM control PWME_PWME6 = 0;
PWME_PWME7 = 0; //disable all outputs PWMCLK_PCLK6 = 1; //SB
中学组一等奖作品
PWMCLK_PCLK7 = 1; //SB PWMCTL_CON67 = 1; PWMSCLB = 4;
PWMPER67 = 40000; //67: 50Hz
PWMDTY67 = PWMDTY67_WarmUp; //67: 7.5% PWMPOL_PPOL7 = 1; PWMCAE_CAE7 = 0; PWMCNT6 = 0; PWMCNT7 = 0; PWME_PWME6 = 1; PWME_PWME7 = 1; }
4.3. 上位机控制程序
救援车需要完成的功能是:提取GSM模块收到的求救短信,并获取目标位置;通过无线模块与救援车进行通讯,提取实时位置,发出控制指令。
上位机控制程序使用Visual C#进行编写。 以上功能所涉及的软件功能有: 1.串口数据收发; 2.短信内容分析;
3.求救者及救援车的位置显示; 4.3.1. 串口收发数据
Visual C#提供了SerialPort控件,从而大大简化了上位机串口收发数据程序的编写。只需要对SerialPort对象进行串口号(PortName)、波特率(BaudRate)等属性进行设置,就完成了串口的初始化,之后可以直接调用相关成员函数完成数据的收发工作。
SerialPort对象的初始化过程为: private void MyInitialize() {
GSM_Port = new SerialPort(\
comboBox_PortName_1.Text = GSM_Port.PortName;
comboBox_BaudRate_1.Text = Convert.ToString(GSM_Port.BaudRate); GSM_Port.DataReceived += new
System.IO.Ports.SerialDataReceivedEventHandler(this.serialPort1_DataReceived);
GSM_Port.ReceivedBytesThreshold = 1;
//some other codes? }
通过串口接收数据的服务函数为:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
this.textBox_Receive_1.Invoke(new MethodInvoker(delegate() {
43
第二届“北斗杯”全国青少年科技创新大赛优秀作品
String GSM_DataReceived;
GSM_DataReceived = GSM_Port.ReadExisting();
textBox_Receive_1.AppendText(GSM_DataReceived); textBox_Receive_1.ScrollToCaret();
//some other codes... })); }
4.3.2. 短信内容分析
完成短信的接收之后,就需要调用函数,对短信内容进行分析,也就是从字符串中寻找含有经纬度信息的语句段,并将其转换为以浮点数形式表示的经纬度信息,用作进一步的处理。具体过程为:
private void GSM_ProcessData() {
Int32 LatitudeIndex; Int32 LongitudeIndex; Int32 TimeDateIndex; Int32 PhoneNumberIndex; Double Degree; Double Minute;
String Kart_CommandMessage;
LatitudeIndex = Target_Message.IndexOf(\ Degree = Convert.ToDouble(
(Convert.ToInt32(Target_Message[LatitudeIndex + 4]) - 48) * 100
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 5]) - 48) * 10
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 6]) - 48));
Minute = Convert.ToDouble(
(Convert.ToInt32(Target_Message[LatitudeIndex + 7]) - 48) * 10
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 8]) - 48) * 1
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 10]) - 48) * 0.1
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 11]) - 48) * 0.01
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 12]) - 48) * 0.001
+ (Convert.ToInt32(Target_Message[LatitudeIndex + 13]) - 48) * 0.0001);
中学组一等奖作品
GSM_Latitude = new Latitude(Degree, Minute);
LongitudeIndex = Target_Message.IndexOf(\ Degree = Convert.ToDouble(
(Convert.ToInt32(Target_Message[LongitudeIndex + 4]) - 48) * 100
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 5]) - 48) * 10
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 6]) - 48));
Minute = Convert.ToDouble(
(Convert.ToInt32(Target_Message[LongitudeIndex + 7]) - 48) * 10
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 8]) - 48) * 1
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 10]) - 48) * 0.1
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 11]) - 48) * 0.01
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 12]) - 48) * 0.001
+ (Convert.ToInt32(Target_Message[LongitudeIndex + 13]) - 48) * 0.0001);
GSM_Longitude = new Longitude(Degree, Minute);
TimeDateIndex = Target_Message.IndexOf(\
GSM_TimeDataInfo = Target_Message.Substring(TimeDateIndex + 3, 20);
PhoneNumberIndex = Target_Message.IndexOf(\ GSM_PhoneNumberInfo =
Target_Message.Substring(PhoneNumberIndex, 14);
textBox_Latitude_1.Text =
Target_Message.Substring(LatitudeIndex + 4, 10);
textBox_Longitude_1.Text =
Target_Message.Substring(LongitudeIndex + 4, 10);
textBox_Time.Text = GSM_TimeDataInfo;
textBox_Number.Text = GSM_PhoneNumberInfo; textBox_Message_1.Text = Target_Message;
Kart_CommandMessage = String.Concat(\Target_Message.Substring(LatitudeIndex + 4, 10));
Kart_CommandMessage = String.Concat(Kart_CommandMessage,
45