EME(月面反射通訊)/OSCAR(業餘衛星通信)用控制器

/***************************************************************************************************

EME(月面反射通訊)/AMAST(業餘衛星通信)用控制器 (核心碼)

利用 控制轉向設備(定向天線) 自動/手動 達成 EME / AMAST 時透過軟件追逐目標之功能

(PCB線路圖,程式檔案在頁尾)

主核心: PIC16F877A

使用週邊: GY-26 (電子羅盤0~360)[0~3600 通訊]

SCA60C N1000060 單軸傾角傳感器

(傾角器-90~+90)[0.5~4.5 VDC ] 為了要能偵測超過下限,下限建議至少定在0.8~1左右

MAX232 (與上位機通訊)

1602 (液晶顯示)

液晶顯示: 第一行 顯示 "方位角 傾角 自動A/手動M 模式"

第二行 顯示 "目前狀態" 左/右/上/下 旋轉"

支援指令: GS-232A (部份指令)

C //要求 水平角度

B //要求 傾角

C2 //要求 水平 + 傾角

M //指令 前往 Mxxx 水平角度xxx

W //指令 前往 Wxxx yyy 水平角度xxx 傾角yyy

S //指令 All Stop

R //指令 Clockwise Rotation

L //指令 Counter Clockwise Rotation

A //指令 CW/CCW Rotation Stop

U //指令 UP Direction Rotation

D //指令 DOWN Direction Rotation

E //指令 UP/DOWN Direction Rotation Stop

I/O定義:

定義 TRISx 1為輸入/ 0為輸出 / x 為未始用(1) (TRISA只有6個Bit)

TRISA x x 0 x 0 0 0 1 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左

TRISB 0 0 0 0 0 0 0 0 <--- LCD IO 輸出

TRISC 1 0 0 0 0 0 0 0 <--- Bit01: 停右 /Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入

TRISD 0 0 0 0 0 0 0 0 <--- Bit01267:R.L.OUTPUT / Bit345:LCD command

定義 PORTx 1為高電平/ 0為低電平 / x 為未始用

(TRISA只有6個Bit)電壓輸入口設低電平/其他需要改變狀態(拉成低電平)的設成高電平/再其他亦可都設成高電平

PORTA x x 1 1 1 1 1 0 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左輸入

PORTB 1 1 1 1 1 1 1 1 <--- LCD IO 輸出

PORTC 1 0 0 0 0 0 0 0 <--- Bit01:停右輸入/Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入

PORTD 1 1 1 1 1 1 1 1 <--- Bit01267:R.L.OUTPUT (高電平 = 1 = 不動作 )/ Bit345:LCD command

接線注意 : 控制雲台轉向的繼電器實際接線時,

將110V電源其中一線接到 上(COM) 再將 上(NC)->下(COM) 以此類推 ->左-->右

這樣可以防止萬一繼電器同時動作時,110V的控制電源同時輸出(雖然程式有保護了,還是要有硬線防呆!)

PS.控制線接在NO

維護記錄: 2012-07-20

***************************************************************************************************/

#include <pic.h> //頭文件在HI-TECH安裝目錄下\HI-TECH Software\PICC\std\9.60\include

#include <stdio.h>

#include <string.h>

#define uchar unsigned char

#define uint unsigned int

#define GY_26_ADDR 0xE0 //定義電子指南針器件地址(出廠默認為0XE0)

#define rs RD5 //LED 命令/數據選擇

#define rw RD4 //LED 讀寫口

#define e RD3 //LED 鎖存控制

#define Dataport PORTB //LED 數據口定義

void delay_20us(uint nus);

void mcu_init(void);

void nms_delay(uint nms);

uint get_GY_26(uchar read_begin_address,uchar GY_26_cmd);

uint get_AD(void);

void conversion(uint i);

void cmdIU(uint i);

//iic使用函數********************************//

void iic_Start(void){SEN=1;while(SEN);} //啟動iic

void iic_Stop (void){PEN=1;while(PEN);} //停止iic

void iic_rest (void){RSEN=1;while(RSEN);} //重啟iic

void iic_Write8Bit(uchar x){SSPIF=0;SSPBUF=x;while(!SSPIF);SSPIF=0;}//向iic總線寫8bit數據

uchar iic_read8Bit(void){RCEN=1;while(!BF);ACKEN=1;while(ACKEN);return SSPBUF;}//向iic總線讀8bit數據

//****LCD定位點*********012345678901234567***************//

bank2 uchar dis1[18]={"---- BV4WD -----\0"}; //顯示兩行

bank2 uchar dis2[18]={"-- Waitting ! --\0"}; //開機預設的顯示畫面,等待雲臺離開死點後進入程式會刷新

bank2 unsigned int CMP_DATA;

bank2 unsigned int result;

bank3 uchar disAZ[14]={"+00000000000\0"}; //水平

bank3 uchar disEL[14]={"+00000000000\0"}; //傾角

bank3 uchar disAZEL[14]={"+0000+000000\0"}; //水平 + 傾角

bank1 uint AZ; // 檢測到的目前 水平角度

bank1 uint EL; // 檢測到的目前 傾角

bank1 uint cmd_AZ; // 指令 至 水平角度

bank1 uint cmd_EL; // 指令 至 傾角

//**************************************以下僅做旗標用***********//

bank1 int rd_AZ; //要求 水平角度

bank1 int rd_EL; //要求 傾角

bank1 int rd_AZEL; //要求 水平 + 傾角

bank1 int rd_M; //指令 前往 Mxxx 水平角度xxx

bank1 int rd_W; //指令 前往 Wxxx yyy 水平角度xxx 傾角yyy

bank1 int rd_S; //指令 All Stop

bank1 int rd_R; //指令 Clockwise Rotation

bank1 int rd_L; //指令 Counter Clockwise Rotation

bank1 int rd_A; //指令 CW/CCW Rotation Stop

bank1 int rd_U; //指令 UP Direction Rotation

bank1 int rd_D; //指令 DOWN Direction Rotation

bank1 int rd_E; //指令 UP/DOWN Direction Rotation Stop

//**************************************以上僅做旗標用***********//

//***********以下變數使用 BANK1 *****************************

bank1 int RecTemp; //rs-232資料讀入暫存

bank1 uchar RecArray[12]; //將 RS-232 命令 寫入EEPROM用字串介面

//*********************************************

//數據轉換,十六進制數據轉換成10進制

//輸入十六進制範圍:0x0000-0x270f(0-9999)

//結果分成個十百千位,以ascii存入顯示區

//**********************************************

void conversion(unsigned int i)

{

unsigned int j;

j=i; //將j=i 使用 j 做PWM運算

AZ=i/10;

/* 不需羅盤0~360度 轉 PWM 0~5vdc 時, 本區關閉 節省資源

PR2 = 0b10111110; //經實測 PR2/T2CON/CCP1CON 使用固定數值

T2CON = 0b00000100; //CCPR1L從 0~190 大約可對應 0~5vDC輸出

CCP1CON = 0b00111100; //j=0~3600 3600/19 =189(取整數)

CCPR1L =(j/19)+1; //189+1=190 ;+1之後表示 0度~2度會有 "1"

//所以精度大約為2度(後面定位時會可採用+/-2度及算定位完成)

*/

dis1[3]=i/1000+0x30; // i : 取自電子羅盤的角度

i=i%1000; //取餘數運算

dis1[4]=i/100+0x30;

i=i%100; //取餘數運算

dis1[5]=i/10+0x30;

i=i%10; //取餘數運算

dis1[6]=0xDF; //(度)

//*************************************************************

//這是電壓顯示部份,不顯示 不需運算

//*************************************************************

/*顯示 羅盤0~360度 轉 PWM 0~5vdc 時,的理論電壓值

j=(((j/19)+1)*100)/38; // j : 計算出來的理論電壓

dis1[10]=j/100+0x30;

j=j%100; //取餘數運算

dis1[11]=0x2E; //.(小數點)

dis1[12]=j/10+0x30;

j=j%10; //取餘數運算

dis1[13]=j+0x30;

dis1[14]=0x30;

dis1[15]=0x56; // V

//以下是 計算/顯示 至 小數位 但無意義

dis1[3]=i/1000+0x30; // i : 取自電子羅盤的角度

i=i%1000; //取餘數運算

dis1[4]=i/100+0x30;

i=i%100; //取餘數運算

dis1[5]=i/10+0x30;

i=i%10; //取餘數運算

dis1[6]=0x2E; //.(小數點)

dis1[7]=i+0x30;

dis1[8]=0xDF; //(度)

*/

//*****************************************

//將水平 度數值放入暫存區等候RS-232 調用

//*****************************************

disAZ[2]=dis1[3]; //水平角度 百位

disAZ[3]=dis1[4]; //水平角度 十位

disAZ[4]=dis1[5]; //水平角度 個位

//*****************************************

//將水平 + 傾角 角度放入暫存區等候RS-232 調用

//*****************************************

disAZEL[2]=dis1[3]; //水平角度 百位

disAZEL[3]=dis1[4]; //水平角度 十位

disAZEL[4]=dis1[5]; //水平角度 個位

}

//**************************************************************************************************

//數據轉換,AD轉換結果

//輸入十六進制範圍:0x0000-0x03FF(0-1023)

//結果分成個十百千位,以ascii存入顯示區

//**************************************************************************************************

void conversion2(unsigned int d)

{

int ad1,ad2,ad3,ad4; //定義6個AD轉換臨時變量 整數常數 int 佔有 16 個 位元

//float temp,temp1; //定義4個計算臨時變量 浮點常數 float 佔有 32 個 位元

float temp,temp1,ed1,ed2; //定義4個計算臨時變量 浮點常數 float 佔有 32 個 位元

temp=d*5.0/1023; //暫存AD轉換的結果 10位AD 2的10次方=1024

temp1=temp; //將數值暫存 temp 計算電壓 / temp1 計算角度

ad1=(int)temp; //計算輸入電壓

ad2=((int)(temp*10)-ad1*10);

ad3=((int)(temp*100)-ad1*100-ad2*10);

ad4=((int)(temp*1000)-ad1*1000-ad2*100-ad3*10);

//*************************************************************

//這是電壓顯示部份,不顯示 不需運算

//*************************************************************

//dis2[10]=(int)temp+0x30; //顯示 個位

//dis2[11]=0x2E; //.(小數點)

//dis2[12]=((int)(temp*10)-ad1*10)+0x30; //顯示 小數第一位

//dis2[13]=((int)(temp*100)-ad1*100-ad2*10)+0x30; //顯示 小數第二位

//dis2[14]=((int)(temp*1000)-ad1*1000-ad2*100-ad3*10)+0x30; //顯示 小數第三位

//dis2[15]=0x56; // V

//EEPROM_WRITE(0x08,0x01);

//EEPROM_WRITE(0x09,0x04);

//********************************************************************************

//(傾角器-90~+90[共180])[0.5~4.5 VDC ] 為了要能偵測超過下限,下限建議至少定在高於0.8v

//4.5-0.5=4 4/2=2 (VDC)<--只取中間90度用 下限取1.5v/上限取1.5+2=3.5V/中點2.5v

//********************************************************************************

ed1=1.5; //電壓下限 0度

ed2=3.5; //電壓上限 90度

//*************************************************************

temp1=(temp1-ed1)*(90.0/(ed2-ed1)); //計算角度 0~90

EL=(int)temp1;

ad1=((int)(temp1/10)); //十

ad2=((int)(temp1-ad1*10)); //個

ad3=((int)(temp1*100)-ad1*10-ad2); //小數

dis1[11]=((int)(temp1/10))+0x30; //顯示 十位

dis1[12]=((int)(temp1-ad1*10))+0x30; //顯示 個位

dis1[13]=0xDF; //(度)

//*************************************************************

//可計算/顯示 至 小數位 但無意義

//*************************************************************

//dis2[6]=0x2E; //.(小數點)

//dis2[7]=((int)(temp1*100)-ad1*10-ad2)+0x30; //顯示 小數第一位

//*****************************************

//將傾角 度數值放入暫存區等候RS-232 調用

//*****************************************

disEL[2]=0x30; //水平角度 百位

disEL[3]=dis1[11]; //水平角度 十位

disEL[4]=dis1[12]; //水平角度 個位

//*****************************************

//將 傾角 角度放入暫存區等候RS-232 調用

//*****************************************

disAZEL[7]=0x30; //傾角角度 百位

disAZEL[8]=dis1[11]; //傾角角度 十位

disAZEL[9]=dis1[12]; //傾角角度 個位

if(temp<ed1) //當輸入電壓低於 電壓下限

{

disEL[2]=0x30; //傾角角度 百位 設0

disEL[3]=0x30; //傾角角度 十位 設0

disEL[4]=0x30; //傾角角度 個位 設0

disAZEL[7]=0x30; //水平+傾角的 傾角角度 百位 設0

disAZEL[8]=0x30; //水平+傾角的 傾角角度 十位 設0

disAZEL[9]=0x30; //水平+傾角的 傾角角度 個位 設0

dis1[11]='L';

dis1[12]='o';

}

if(temp>ed2) //當輸入電壓高於 電壓上限

{

disEL[2]=0x30; //傾角角度 百位 設0

disEL[3]=0x39; //傾角角度 十位 設9

disEL[4]=0x30; //傾角角度 個位 設0

disAZEL[7]=0x30; //水平+傾角的 傾角角度 百位 設0

disAZEL[8]=0x39; //水平+傾角的 傾角角度 十位 設9

disAZEL[9]=0x30; //水平+傾角的 傾角角度 個位 設0

dis1[11]='O';

dis1[12]='v';

}

}

//**************************************************************************************************

//數據轉換,ascii 轉換成 十六進制數據

//**************************************************************************************************

void con_WB(void)

{

unsigned int k,p;

k=0;

p=0;

k=(RecArray[1]-0x30)*100;

k=k+(RecArray[2]-0x30)*10;

k=k+(RecArray[3]-0x30);

if(RecArray[0]=='M'|RecArray[0]=='W')

{

cmd_AZ=(int)k;

}

/*

if(k>=0xFF) //寫入 EEPROM 需耗費時間較長 不需要時不寫入

{

k=k-0xff; //大於 256

EEPROM_WRITE(0x00,0x01); //寫入 水平數值 高位數 至EEPROM 位址0x00

EEPROM_WRITE(0x01,k); //寫入 水平數值 低位數 至EEPROM 位址0x01

}

else

{

EEPROM_WRITE(0x00,0x00); //寫入 水平數值 高位數 至EEPROM 位址0x00

EEPROM_WRITE(0x01,k); //寫入 水平數值 低位數 至EEPROM 位址0x01

}

*/

if(rd_W==1)

{

p=(RecArray[5]-0x30)*100;

p=p+(RecArray[6]-0x30)*10;

p=p+(RecArray[7]-0x30);

if(RecArray[0]=='W')

{

cmd_EL=(int)p;

}

/*

if(p>=0xFF) //寫入 EEPROM 需耗費時間較長 不需要時不寫入

{

p=p-0xff; //大於 256

EEPROM_WRITE(0x03,0x01); //寫入 傾角數值 高位數 至EEPROM 位址0x03

EEPROM_WRITE(0x04,p); //寫入 傾角數值 低位數 至EEPROM 位址0x04

}

else

{

EEPROM_WRITE(0x03,0x00); //寫入 傾角數值 高位數 至EEPROM 位址0x03

EEPROM_WRITE(0x04,p); //寫入 傾角數值 低位數 至EEPROM 位址0x04

}

*/

}

}

//**************************************************************************************************

//單片機初始化

//**************************************************************************************************

void mcu_init(void)

{

//TRISC=0x80; //IIC通信引腳設為輸入

SSPSTAT = 0x80; //IIC設置

SSPCON = 0x38; //IIC設置

SSPCON2 = 0x00; //IIC設置

SSPADD = 50; //IIC設置

}

//**************************************************************************************************

//延時大約20us

//**************************************************************************************************

void delay_20us(uint nus)

{ uchar i;

while(--nus){

for(i=2;i>0;i--);

}

}

//**************************************************************************************************

//延時大約1ms

//**************************************************************************************************

void nms_delay(uint nms)

{

while(nms--)

delay_20us(50);

}

//**************************************************************************************************

//延時

//**************************************************************************************************

void delay(uint time)

{

uint i,j;

for(i = 0;i < time; i++);

{

for(j = 0;j <30; j++);

}

}

//**************************************************************************************************

//從IIC總線獲得電子指南針GY-26數據

//從開始地址連續讀出兩個8bit的值,併合成16bit數據

//**************************************************************************************************

uint get_GY_26(uchar read_begin_address,uchar GY_26_cmd)

{

unsigned int temp;

iic_Start(); //iic啟動時序

iic_Write8Bit(GY_26_ADDR); //寫指南針器件地址

iic_Write8Bit(0); //寫命令

iic_Write8Bit(GY_26_cmd); //寫指南針命令

iic_Stop(); //iic寫停止時序

nms_delay(60); //延時,可執行其他程序 原始值:55

iic_Start(); //iic啟動時序

ACKDT = 0; //允許應答ACK

//*******************************************************************************

//需修正磁偏角時使用「台灣磁偏角目前試定為3.5度」

//第一次使用時最好修正,因為GY-26大部分修正偏角是6度(或10度)

//*******************************************************************************

//iic_Write8Bit(0x03); //發送設定磁偏角高8位命令。

//iic_Write8Bit(0x00); //發送磁偏角高8位的數據。

//iic_Write8Bit(0x03); //發送設定磁偏角低8位命令

//iic_Write8Bit(0x23); //發送磁偏角低8位的數據。此時磁偏角被設定為3.5度

iic_Write8Bit(GY_26_ADDR); //寫指南針器件地址

iic_Write8Bit(read_begin_address); //寫指南針內部數據地址

iic_rest(); //iic重啟時序

iic_Write8Bit(GY_26_ADDR+1); //指南針器件地址+1=讀

temp=iic_read8Bit(); //讀出8位數據

temp<<=8; //保存數據

ACKDT = 1; //允許應答NO_ACK

temp+=iic_read8Bit(); //讀出8位數據

iic_Stop(); //發送停止時序

return temp; //返回本次測量數值

}

//**************************************************************************************************

//從AN0讀取轉換電壓的相對值

//從ADRESH ADRESL 讀出兩個8bit的值,併合成16bit數據

//**************************************************************************************************

uint get_AD()

{

unsigned int temp;

result=0; //轉換結果清0

ADGO=0x01; //開啟轉換過程

delay(50); //保證採樣延時

//ADGO=0x01; ////ADGO=1放在此採樣不行

while(ADGO); //等待轉換完成

temp=ADRESH; //讀出8位數據

temp<<=8; //保存數據

temp+=ADRESL; //讀出8位數據

return temp; //返回本次測量數值

}

//**************************************************************************************************

//IO初始化操作

//定義 TRISx 1為輸入/ 0為輸出 / x 為未始用(1) (TRISA只有6個Bit)

// TRISA x x 0 x 0 0 0 1 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左

// TRISB 0 0 0 0 0 0 0 0 <--- LCD IO 輸出

// TRISC 1 0 0 0 0 0 0 0 <--- Bit01: 停右 /Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入

// TRISD 0 0 0 0 0 0 0 0 <--- Bit01267:R.L.OUTPUT / Bit345:LCD command

//

//定義 PORTx 1為高電平/ 0為低電平 / x 為未始用

// (TRISA只有6個Bit)電壓輸入口設低電平/其他需要改變狀態(拉成低電平)的設成高電平/再其他亦可都設成高電平

// PORTA x x 1 1 1 1 1 0 <--- Bit0:傾角電壓輸入 /Bit1:手[自]動(接地=手動) /Bit235:上下左輸入

// PORTB 1 1 1 1 1 1 1 1 <--- LCD IO 輸出

// PORTC 1 0 0 0 0 0 0 0 <--- Bit01:停右輸入/Bit2:PWM輸出/Bit34:I2C總線/Bit6:RS-232TX輸出/Bit7:RS-232RX輸入

// PORTD 1 1 1 1 1 1 1 1 <--- Bit01267:R.L.OUTPUT (高電平 = 1 = 不動作 )/ Bit345:LCD command

//**************************************************************************************************

void IO_init(void)

{


TRISA=0x01; //RA0設置為輸入 00 0001

PORTA=0x3e; //設置RA0為低電平

TRISC=0x80; //RC7設置為輸入 1000 0000

PORTC=0xff; //初始化為高電平

TRISB=0x00; //RB設置為輸出 LCD IO

PORTB=0xff; //初始化為高 LCD IO 為高電平

TRISD=0x00; //RD設置為輸出 LCD command

PORTD=0b11111111; //初始化 LCD command(Bit345) 為高電平 /R.L.OUTPUT為高電平

ADCON1=0X8E; //1000 1110 A/D 轉換用參數 需查表 [PIC16F87XA單片機說明書.pdf p.129~]

ADCON0=0X41; //0100 0001 A/D 轉換用參數 需查表 [PIC16F87XA單片機說明書.pdf p.128~]

}

//**************************************************************************************************

//雲臺初始化操作 (離開限位點)

//向上轉3秒 向下轉2秒

//向左轉3秒 向右轉2秒

//**************************************************************************************************

void Init_wt(void)

{

/*

RD0=0x00;

RD1=0x00;

RD6=0x00;

RD7=0x00;

nms_delay(1000);

RD2=0x01; //RD2 失能(亮)

nms_delay(1000); //可將訊號接至 雲臺旁 閃爍紅燈警示

RD2=0x00; //RD2 致能(確認完成開機,控制雲臺電源可輸出[實驗板LED亮->熄滅])

nms_delay(1000); //等待 進入旋轉初始化

RD0=0x01; //指令 UP Direction Rotation

RD6=0x01; //指令 Counter Clockwise Rotation

nms_delay(3000);

RD0=0x00; //指令 UP Direction Rotation

RD6=0x00; //指令 Counter Clockwise Rotation

RD0=0x00; //指令 UP Direction Rotation

nms_delay(500);

RD1=0x01; //指令 DOWN Direction Rotation

RD7=0x01; //指令 Clockwise Rotation

nms_delay(3000);

RD1=0x00; //指令 DOWN Direction Rotation

RD7=0x00; //指令 Clockwise Rotation

nms_delay(500);

*/

nms_delay(1000); //等待

//*******************************************************************************

//完成轉動後重新將LCD內容刷新

//*******************************************************************************

dis1[0]='A';

dis1[1]='Z';

dis1[2]=':';

dis1[3]='0';

dis1[4]='0';

dis1[5]='0';

dis1[6]=' ';

dis1[7]=' ';

dis1[8]='E';

dis1[9]='L';

dis1[10]=':';

dis1[11]='0';

dis1[12]='0';

dis1[13]=' ';

dis1[14]=' ';

dis1[15]=' ';

dis2[0]='-';

dis2[1]='-';

dis2[2]='-';

dis2[3]='-';

dis2[4]='-';

dis2[5]='-';

dis2[6]='-';

dis2[7]='-';

dis2[8]='-';

dis2[9]='-';

dis2[10]='-';

dis2[11]='-';

dis2[12]='-';

dis2[13]='-';

dis2[14]='-';

dis2[15]='-';

}

//**************************************************************************************************

//向LCD寫一命令

//**************************************************************************************************

wcode(uchar t)

{

rs=0; // 寫的是命令

rw=0; // 寫狀態

e=1; //使能

Dataport=t; //寫入命令

delay(45); //等待寫入,如果時間太短,會導致液晶無法顯示

e=0; //數據的鎖定

}

//**************************************************************************************************

//向LCD寫一數據

//**************************************************************************************************

wdata(uchar t)

{

rs=1; // 寫的是數據

rw=0; // 寫狀態

e=1; //使能

Dataport=t; //寫入數據

delay(45); //等待寫入,如果時間太短,會導致液晶無法顯示

e=0; //數據的鎖定

}

//**************************************************************************************************

//LCD顯示第一行

//**************************************************************************************************

xian1(void)

{

uchar i;

wcode(0x80); //設置第一行顯示地址

for(i=0;i<16;i++) //循環16次,寫完1行

{

wdata(dis1[i]); //寫入該行數據

}

}

//**************************************************************************************************

//LCD顯示第二行

//**************************************************************************************************

xian2(void)

{

uchar i;

wcode(0xc0); //設置第二行顯示地址

for(i=0;i<16;i++) //循環16次,寫完1行

{

wdata(dis2[i]); //寫入該行數據

}

}

//**************************************************************************************************

//LCD 初始化

//**************************************************************************************************

InitLCD(void)

{

wcode(0x01); //清屏

wcode(0x06); //輸入方式控制,增量光標不移位

wcode(0x0e); //顯示開關控制

wcode(0x38); //功能設定:設置16x2顯示,5x7顯示,8位數據接口

}

//**************************************************************************************************

//初始化串口

//**************************************************************************************************

void init_com( void )

{

TXSTA=0x24;//發送數據控制位配置00100100,異步方式、高波特率,波特率=Fosc/16*(SPBTG+1);

//TXSTA寄存器的D5(TXEN)=1,啟動UART的發送功能

RCSTA=0x90;//接收數據控制位配置10010000,設置連續接收數據

//RCSTA寄存器的D4(CREN)=1,啟動UART的接收功能

SPBRG=25; //設置波特率9600,系統時鐘4MHZ,波特率=4000000/16/(25+1)=9615(Bps) 51

//設置波特率4800,系統時鐘4MHZ,波特率=4000000/16/(51+1)=4807(Bps)

RCIE=1; //接收中斷使能

TXIE=0; //發送中斷使/失能

PEIE=1; //INTCON的D6(PEIE)=1,外圍中斷開關打開

RCIF=0;

RCREG=0;

GIE=1; //總中斷開啟

}

//**************************************************************************************************

//寫RS-232

//**************************************************************************************************

void WriteByte(unsigned char byte) {

while(!TXIF);

{

TXREG = byte;

}

}

//**************************************************************************************************

//向RS-232寫一字串數據

//**************************************************************************************************

void WriteStringConst(const unsigned char* str)

{

int n,m;

for(n=0;n<=11;n++)

{

//TXREG = str[n];

WriteByte(str[n]);

}

}

//**************************************************************************************************

//雲臺轉向控制

// 選用的雲臺 傾角 動作時會稍微干擾電子羅盤

// 雖然已經將 羅盤 與 馬達 距離拉開,但在做 傾角 動作時,還是先 不旋轉 以免因為誤判角度而亂轉

//**************************************************************************************************

conTIO(void)

{

RD0= !rd_U; //指令 UP Direction Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作)

RD1= !rd_D; //指令 DOWN Direction Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作)

if(rd_U==0&&rd_D==0) //傾角動作優先,傾角動作完成之後再旋轉

{

RD6= !rd_L; //指令 Counter Clockwise Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作)

RD7= !rd_R; //指令 Clockwise Rotation(反邏輯 單片機輸出"0"=低電平=繼電器動作)

}

}

//**************************************************************************************************

//check 資料要求 COMMAND

//

//int rd_AZ; //要求 水平角度

//int rd_EL; //要求 傾角

//int rd_AZEL; //要求 水平 + 傾角

//**************************************************************************************************

cmdCHK(void)

{

if(rd_AZ==1)

{

WriteStringConst(disAZ);

rd_AZ=0;

}

if(rd_EL==1)

{

WriteStringConst(disEL);

rd_EL=0;

}

if(rd_AZEL==1)

{

WriteStringConst(disAZEL);

rd_AZEL=0;

}

}

//**************************************************************************************************

//雲臺自動轉向 COMMAND

//

//int rd_M; //自動指令 前往 Mxxx 水平角度xxx

//int rd_W; //自動指令 前往 Wxxx yyy 水平角度xxx 傾角yyy

//int rd_S; //指令 All Stop

//int rd_R; //指令 Clockwise Rotation

//int rd_L; //指令 Counter Clockwise Rotation

//int rd_A; //指令 CW/CCW Rotation Stop

//int rd_U; //指令 UP Direction Rotation

//int rd_D; //指令 DOWN Direction Rotation

//int rd_E; //指令 UP/DOWN Direction Rotation Stop

//**************************************************************************************************

void turn_cmd(void)

{

//if(cmd_AZ>AZ&&(cmd_AZ-AZ)>3 &&(cmd_AZ-AZ)<30)

if(cmd_AZ>AZ&&(cmd_AZ-AZ)>3)

{

nms_delay(100); //防止繼電器高速跳動

rd_R=1;

rd_L=0;

}

//if(AZ>cmd_AZ&&(AZ-cmd_AZ)>3&&(AZ-cmd_AZ)<30)

if(AZ>cmd_AZ&&(AZ-cmd_AZ)>3)

{

nms_delay(100); //防止繼電器高速跳動

rd_R=0;

rd_L=1;

}

//if(AZ >345 && cmd_AZ <15 ) // tracking cross left 過 360'

//{

// rd_R=1;

//}

//if(AZ <15 && cmd_AZ >345 ) // tracking cross right 過 360'

//{

// rd_L=1;

//}

if(cmd_AZ>AZ&&(cmd_AZ-AZ)<3)

{

rd_R=0;

}

if(AZ>cmd_AZ&&(AZ-cmd_AZ)<3)

{

rd_L=0;

}

if(rd_R==0&&rd_L==0)

{

rd_M=0;

}

if(rd_W==1)

{

//if(cmd_EL>EL&&(cmd_EL-EL)>2&&(cmd_EL-EL)<20&&EL<90)

if(cmd_EL>EL&&(cmd_EL-EL)>2&&EL<90)

{

nms_delay(100); //防止繼電器高速跳動

rd_U=1;

rd_D=0;

}

//if(EL>cmd_EL&&(EL-cmd_EL)>2&&(EL-cmd_EL)>20&&EL>0)

if(EL>cmd_EL&&(EL-cmd_EL)>2&&EL>0)

{

nms_delay(100); //防止繼電器高速跳動

rd_D=1;

rd_U=0;

}

if(cmd_EL>EL&&(cmd_EL-EL)<2)

{

rd_U=0;

}

if(EL>cmd_EL&&(EL-cmd_EL)<2)

{

rd_D=0;

}

if(EL==0&&cmd_EL==0)

{

rd_D=0;

rd_U=0;

}

if(rd_R==0&&rd_L==0&&rd_U==0&&rd_D==0)

{

rd_W=0;

}

}

if(rd_A==1)

{

rd_R=0;

rd_L=0;

rd_A=0;

}

if(rd_E==1)

{

rd_D=0;

rd_U=0;

rd_E=0;

}

}

//**************************************************************************************************

//check 雲臺轉向 指示 及 過頭.回一點 控制

//

//int rd_M; //自動指令 前往 Mxxx 水平角度xxx

//int rd_W; //自動指令 前往 Wxxx yyy 水平角度xxx 傾角yyy

//int rd_S; //指令 All Stop

//int rd_R; //指令 Clockwise Rotation

//int rd_L; //指令 Counter Clockwise Rotation

//int rd_A; //指令 CW/CCW Rotation Stop

//int rd_U; //指令 UP Direction Rotation

//int rd_D; //指令 DOWN Direction Rotation

//int rd_E; //指令 UP/DOWN Direction Rotation Stop

//**************************************************************************************************

void turn_dsp(void)

{

if(dis1[11]=='L'&&dis1[12]=='o'&&result>>0) //指令 傾角過低 low(回頭)(當 傾角 輸入=0V(將該腳位接地) 時 不做「過頭回一點」的控制)

{

RD1=!0x00;

RD0=!0x01;

nms_delay(300);

RD1=!0x00;

RD0=!0x00;

}

if(dis1[11]=='O'&&dis1[12]=='v'&&result>>0) //指令 傾角過高 over(回頭)(當 傾角 輸入=0V(將該腳位接地) 時 不做「過頭回一點」的控制)

{

RD0=!0x00;

RD1=!0x01;

nms_delay(300);

RD1=!0x00;

RD0=!0x00;

}

//******012345678901234567***************//

//dis2{"Turn! Right Down\0"};

// {"Turn! Left UP \0"};

// {"------STOP------\0"};

//***********************************//

if(rd_U==1|rd_D==1|rd_L==1|rd_R==1)

{

dis2[0]='T';

dis2[1]='u';

dis2[2]='r';

dis2[3]='n';

dis2[4]='!';

dis2[5]=0x20;

dis2[6]=0x20;;

dis2[7]=0x20;;

dis2[8]=0x20;;

dis2[9]=0x20;;

dis2[10]=0x20;

dis2[11]=0x20;;

dis2[12]=0x20;;

dis2[13]=0x20;;

dis2[14]=0x20;;

dis2[15]=0x20;;

}

if(rd_U==1)

{

dis2[12]=0x20;

dis2[13]='U';

dis2[14]='P';

dis2[15]=0x20;

}

if(rd_D==1)

{

dis2[12]='D';

dis2[13]='o';

dis2[14]='w';

dis2[15]='n';

}

if(rd_L==1)

{

dis2[6]='L';

dis2[7]='e';

dis2[8]='f';

dis2[9]='t';

dis2[10]=0x20;

}

if(rd_R==1)

{

dis2[6]='R';

dis2[7]='i';

dis2[8]='g';

dis2[9]='h';

dis2[10]='t';

}

if(rd_U==0&&rd_D==0)

{

dis2[12]=0x20;

dis2[13]=0x20;

dis2[14]=0x20;

dis2[15]=0x20;

}

if(rd_L==0&&rd_R==0)

{

dis2[6]=0x20;

dis2[7]=0x20;

dis2[8]=0x20;

dis2[9]=0x20;

dis2[10]=0x20;

}

if(rd_U==0&&rd_D==0&&rd_L==0&&rd_R==0)

{

dis2[0]='-';

dis2[1]='-';

dis2[2]='-';

dis2[3]='-';

dis2[4]='-';

dis2[5]='-';

dis2[6]='-';

dis2[7]='-';

dis2[8]='-';

dis2[9]='-';

dis2[10]='-';

dis2[11]='-';

dis2[12]='-';

dis2[13]='-';

dis2[14]='-';

dis2[15]='-';

}

}

//*********************************************

//雲臺 手動 轉向 COMMAND

//

//int rd_S; //指令 All Stop

//int rd_R; //指令 Clockwise Rotation

//int rd_L; //指令 Counter Clockwise Rotation

//int rd_A; //指令 CW/CCW Rotation Stop

//int rd_U; //指令 UP Direction Rotation

//int rd_D; //指令 DOWN Direction Rotation

//int rd_E; //指令 UP/DOWN Direction Rotation Stop

//**********************************************

void PB_cmd(void)

{

rd_M=0;

rd_W=0;

rd_L=0;

rd_R=0;

rd_A=0;

rd_U=0;

rd_D=0;

rd_E=0;

rd_S=0;

if(RA2==0) //檢查按鍵 上

{

nms_delay(5);

if(RA2==0)

{

rd_D=0; //互鎖

rd_U=1;

}

}

else

{

rd_U=0;

}

if(RA3==0) //檢查按鍵 下

{

nms_delay(5);

if(RA3==0)

{

rd_U=0; //互鎖

rd_D=1;

}

}

else

{

rd_D=0;

}

if(RC1==0) //檢查按鍵 左

{ // (RA4 不可以用(無法改變數值+狀態不定) /改用 RC1)

nms_delay(5);

if(RC1==0)

{

rd_R=0;

rd_L=1;

}

}

else

{

rd_L=0;

}

if(RA5==0) //檢查按鍵 右

{

nms_delay(5);

if(RA5==0)

{

rd_L=0;

rd_R=1;

}

}

else

{

rd_R=0;

}

if(RC0==0) //檢查按鍵 停

{

nms_delay(5);

if(RC0==0)

{

rd_L=0;

rd_R=0;

rd_U=0;

rd_D=0;

rd_S=1;

}

}

else

{

rd_S=0;

}

}

//*********************************************

//CHECK STOP COMMAND

//int rd_S; //指令 All Stop

//**********************************************

void CHK_stop(void)

{

if(RC0==0) //檢查按鍵 停

{

nms_delay(5);

if(RC0==0)

{

rd_L=0;

rd_R=0;

rd_U=0;

rd_D=0;

rd_S=1;

}

}

else

{

rd_S=0;

}


}

//**************************************************************************************************

//串口中斷函數

//接收要求或指令 並改變旗標

//int rd_AZ; //要求 水平角度

//int rd_EL; //要求 傾角

//int rd_AZEL; //要求 水平 + 傾角

//

//int rd_M; //指令 前往 Mxxx 水平角度xxx

//int rd_W; //指令 前往 Wxxx yyy 水平角度xxx 傾角yyy

//

//int rd_R; //指令 Clockwise Rotation

//int rd_L; //指令 Counter Clockwise Rotation

//int rd_A; //指令 CW/CCW Rotation Stop

//

//int rd_U; //指令 UP Direction Rotation

//int rd_D; //指令 DOWN Direction Rotation

//int rd_E; //指令 UP/DOWN Direction Rotation Stop

//

//int rd_S; //指令 All Stop

//**************************************************************************************************\

void interrupt usart(void)

{

int i;

if(RCIF)

{

RecArray[i] = RCREG;

i=i++;

//if(RCREG==0x0D|RCREG==0x20)

if(RCREG==0x0D)

{

//if(RecArray[0]==0x43&&rd_M!=1&&rd_W!=1) // 如果抓到開頭為 C 並且無自動指令 M W

if(RecArray[0]==0x43) // 如果抓到開頭為 C 並且無自動指令 M W

{

rd_AZ=1;

}

//if(RecArray[0]==0x42&&rd_M!=1&&rd_W!=1) // 如果抓到開頭為 B 並且無自動指令 M W

if(RecArray[0]==0x42) // 如果抓到開頭為 B 並且無自動指令 M W

{

rd_EL=1;

}

//if(RecArray[0]==0x43 && RecArray[1]==0x32&&rd_M!=1&&rd_W!=1) // 如果抓到開頭為 C2 並且無自動指令 M W

if(RecArray[0]==0x43 && RecArray[1]==0x32) // 如果抓到開頭為 C2 並且無自動指令 M W

{

rd_AZ=0;

rd_EL=0;

rd_AZEL=1;

}

if(RecArray[0]==0x4D) // 如果抓到開頭為 M 水平自動指令

{

rd_M=1;

}

if(RecArray[0]==0x57) // 如果抓到開頭為 W 水平+傾角自動指令

{

rd_W=1;

}

if(RecArray[0]==0x52) // 如果抓到開頭為 R

{

rd_L=0;

rd_R=1;

}

if(RecArray[0]==0x4C) // 如果抓到開頭為 L

{

rd_R=0;

rd_L=1;

}

if(RecArray[0]==0x41) // 如果抓到開頭為 A

{

rd_L=0;

rd_R=0;

rd_A=1;

}

if(RecArray[0]==0x55) // 如果抓到開頭為 U

{

rd_D=0;

rd_U=1;

}

if(RecArray[0]==0x44) // 如果抓到開頭為 D

{

rd_U=0;

rd_D=1;

}

if(RecArray[0]==0x45) // 如果抓到開頭為 E

{

rd_U=0;

rd_D=0;

rd_E=1;

}

if(RecArray[0]==0x53) // 如果抓到開頭為 S

{

rd_M=0;

rd_W=0;

rd_L=0;

rd_R=0;

rd_A=0;

rd_U=0;

rd_D=0;

rd_E=0;

rd_S=1;

}

i=0;

}

if(i>=11)

{

i=0; //如果超過12(0~11)個字元就把i歸零(一直重複,將此次訊號收完,防止溢位)

}

}

}

//**************************************************************************************************

//主函數

//**************************************************************************************************

main()

{

uchar cntl;

//__CONFIG(XT&WDTEN&LVPDIS);//配置,設置為晶振XT方式振蕩,看門狗,禁低電壓編程

__CONFIG(XT&WDTDIS&LVPDIS);//配置,設置為晶振XT方式振蕩,禁看門狗,禁低電壓編程

mcu_init(); //晶片初始化

IO_init(); //IO初始化

init_com(); //初始化串口

InitLCD(); //初始化1602

xian1(); //顯示 等待訊息

xian2(); //顯示 等待訊息

Init_wt(); //初始化雲臺(確保不會正好在 Over0 或是 Over360)

while(1) //進入while死循環

{

result=get_AD(); //讀取傾角電壓

conversion2(result); //數據轉換出個,十,百,千 位

if(rd_U==0&&rd_D==0)

{

CMP_DATA=get_GY_26(1,0x31); //讀取角度

conversion(CMP_DATA); //數據轉換出個,十,百,千 位

}

xian1(); //顯示 第1行刷新

xian2(); //顯示 第2行刷新

conTIO();

cmdCHK();

if(RA1==1) //檢查模式 自動=1 手動=0

{

dis1[15]='A';

if(rd_M==1|rd_W==1)

{

con_WB(); //轉換指令後之「文字」變成「數字」

turn_cmd(); //檢測是否要旋轉

//turn_dsp(); //旋轉狀態顯示

}

CHK_stop(); //檢測是否STOP有按下

turn_dsp(); //旋轉狀態顯示

}

if(RA1==0) //檢查模式 自動=1 手動=0

{

dis1[15]='M';

rd_M=0;

rd_W=0;

PB_cmd(); //掃描按鍵狀態

turn_dsp(); //旋轉狀態顯示

}

}

}