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(); //旋轉狀態顯示
}

  }
}
   

   






ą
Kim Chen,
2012年7月6日 下午11:27
ċ
CH340.7z
(139k)
Kim Chen,
2012年7月1日 上午7:17
ċ
ExpressPCBSetup(pcb 檔案 編輯軟體)[ExpressPCB for XP, 2000 & NT,Vista & Windows 7].7z
(9180k)
Kim Chen,
2012年9月7日 下午8:07
Ċ
Kim Chen,
2012年7月6日 下午11:26
Ċ
Kim Chen,
2013年3月26日 上午1:13
Ċ
Kim Chen,
2013年3月26日 上午1:13
ą
Kim Chen,
2012年8月5日 下午7:00
ą
Kim Chen,
2012年8月5日 下午7:00
Ċ
Kim Chen,
2012年8月5日 下午7:00
Ċ
Kim Chen,
2012年8月5日 下午7:00
ċ
PCB_核心板-Ver012.pcb
(23k)
Kim Chen,
2012年8月5日 下午7:00
ċ
PCB_核心板-Ver013.pcb
(24k)
Kim Chen,
2012年9月7日 下午5:37
ċ
PCB_核心板-Ver014_4線.pcb
(25k)
Kim Chen,
2014年2月22日 上午12:48
ċ
PCB_核心板-Ver014_4線_V2.pcb
(24k)
Kim Chen,
2014年2月22日 上午12:48
ċ
PCB_核心板.pcb
(22k)
Kim Chen,
2012年8月2日 下午11:47
ċ
PCB_通用核心板 Ver001.pcb
(15k)
Kim Chen,
2012年9月8日 上午1:20
Ċ
Kim Chen,
2012年7月6日 下午11:27
Ċ
Kim Chen,
2013年1月28日 上午7:28
ą
Kim Chen,
2012年8月2日 下午11:48
ċ
PL2303.7z
(5009k)
Kim Chen,
2012年7月1日 上午7:17
Ċ
Kim Chen,
2012年7月6日 下午11:28
ċ
_main.hex
(17k)
Kim Chen,
2012年7月20日 上午7:17
ċ
include.7z
(65k)
Kim Chen,
2014年7月30日 下午4:53
ċ
main.c
(34k)
Kim Chen,
2012年7月19日 上午10:14
ą
Kim Chen,
2013年3月26日 上午1:29
ċ
串口調試助手V2.2.7z
(105k)
Kim Chen,
2012年7月1日 上午7:24
Comments