A9101_對講機加入對碼_Pair system_功能
本篇介紹A9101 A50 470Mhz Walkie Talkie 加上配對功能
代碼:
 A9101_A50_Walkie Talkie & Pair system(DR=512Kbps_SR8K8bit_16CHs) CL=18pF_V0.2_0613.zip
A9101_A50_Walkie Talkie & Pair system(DR=512Kbps_SR8K8bit_16CHs) CL=18pF_V0.2_0613.zip
- 當按下 Talk 鍵時(P3.2 =0),系統將從被動端轉變為 Master (TX),主動發射喚醒訊號通知 Slave,來達到連線狀況。 

此應用系統架構於A9101 SubGHz Voice SoC,以下為Demo Code中的操作規格:
- RF data Rate = 512Kbps 
- Codec Sample Rate = 8KHz , A-law壓縮技術 
- Codec AGC ON 
- Talk Key (P3.2) Low/Master ,High/Slave 
- Fix Channel Function (P3.3) Low, Channel =85 (439.761 MHz) 
- 連線使用到 16 個 channel, 4 個 1 組,12ms 後依序切換不同 Channel set, Hopping Table 如下: 
| A50-1 | Channel | 頻率(MHz) | A50-2 | Channel | 頻率(MHz) | 
| 1 | 5 | 468.241 | 1 | 10 | 469.521 | 
| 2 | 35 | 475.921 | 2 | 20 | 472.801 | 
| 3 | 25 | 473.361 | 3 | 30 | 474.641 | 
| 4 | 15 | 470.801 | 4 | 40 | 477.201 | 
| A50-3 | Channel | 頻率(MHz) | A50-4 | Channel | 頻率(MHz) | 
| 1 | 45 | 478.481 | 1 | 50 | 479.761 | 
| 2 | 75 | 486.161 | 2 | 60 | 482.321 | 
| 3 | 65 | 483.601 | 3 | 70 | 484.881 | 
| 4 | 50 | 481.041 | 4 | 80 | 487.441 | 
- 連線頻率查詢,RSSI 查詢,電池電量查詢 
- 靜音(P1.6) Low,增加音量(P1.1) Low,減少音量(P1.0) Low 
- 每個傳輸封包 100Byte,96Byte 是語音資料,剩餘 4Byte 資料內容使用者可自行定義 
- 可選用配對模式(P0.3) Low,需近距離下進行配對,大於設定的 RSSI_threshold 即配對成功,配對模式下 Master/Slave 可選用不同配對 ID(P0.0)Low or ID(P0.1)Low 進行配對,一組廣播 ID,兩組配對 ID,ID 使用者可自行修改,配對成功後也可改用廣播 ID 對兩個 Slave 端進行連線 
==================================================================
配對功能介紹
1. 目前有 3 個裝置分別是 Master,Slave1,Slave2,每進入配對模式一次,"Master/Slave P0.3 都要
先拉 HIGH 再拉 LOW"
2. 針對 Master/Slave1 進行配對,兩裝置選擇 ID1(P0.0)Low,若配對成功 P0.2 會有反覆 High/Low 訊號
3. 針對 Master/Slave2 進行配對,兩裝置選擇 ID2(P0.1)Low,若配對成功 P0.2 會有反覆 High/Low 訊號
4. 若因接收狀況不佳配對失敗, 重複上述動作即可,之後 Slave1(P0.0),Slave2(P0.1) 固定 IO 拉 LOW,以
區分兩種裝置
5.配對成功後,將所有裝置 P0.3 拉 HIGH, 回到語音傳輸模式
若要對 Slave1 進行link,Master P0.0 拉 LOW,Slave2 不會接收到封包
若要對 Slave2 進行link,Master P0.1 拉 LOW,Slave1 不會接收到封包
若 Master P0.0 & P0.1 拉 HIGH,Slave 端不用改 IO 設定,回到廣播 ID 廣播模式,Slave1 & Slave 2 都會出現聲音
Note1: 若還沒配對前,都是用廣播 ID 進行 link
Note2: 按 Reset 取消配對
===================================================================
P.S.配對前需先設置GIO1,GIO2,CKO的配置模式,否則會造成第一次配對成功後,若要再次進入重新配對時會出現無法配對的狀況發生
"
A9101_WriteReg ( GIO1_REG, 0x1C ); //PDN_RX
A9101_WriteReg ( GIO2_REG, 0x00 ); //WTR
A9101_WriteReg ( CKO_REG, 0x00 ); //RCK
"
配對函數:
A9101_Pair();
介紹:
- 判斷P0_3是否拉LOW,先寫入預設廣播ID"Broadcast_ID_Tab" 
	while(Pair_IO==0)// Define P0_3
	{
		WriteID(Broadcast_ID_Tab);2.開啟檢測RSSI
		if(Pair1_IO == 0 || Pair2_IO == 0)//Define P0_0 & P0_1
		{
		    Slave_rssi = 0;
		    link_OK = 0;
    		    A9101_WriteReg (ADC_REG, 0xF2);                                             //RRS=1, FSARS=0,RADC=1,HDM=1 ,RSM=3
    		    A9101_WriteReg (MODEC2_REG, A9101_CONFIGTABLE[MODEC2_REG - CONFIG] | 0x40 ); //ARRSI=1
		    EA = 1;                                                                //enable interrupt
		    ERFINT = 1;3.設定FIFO 長度1Byte,並發射通知Slave端選擇0x01 (ID1) 或 0x02 (ID2)
A9101_WriteReg (FIFO1_REG, 0x01); //FIFO Length = 1 ResetCmd(TXPOINT_RST); if(Pair1_IO == 0) A9101_WriteReg(TX_FIFO, 0x01); else if(Pair2_IO == 0) A9101_WriteReg(TX_FIFO, 0x02);
  4.Master端,將ID Select Number發射出去告知slave端
			if(P3_2 == 0)	//Master
			{				
				for (i=0;i<1;i++)
				{
					Delay1ms(5);
					A9101_WriteReg(INTSW_REG, 0x02);//WTR                                			                                      
					SetCH (75);
					RF_FLAG = 1;  	
					StrobeCmd (CMD_TX);                       					                             
					while (RF_FLAG);   
					StrobeCmd (CMD_STBY); //Tx finish Entry PLL MODE
				        Delay1ms(1);  5.TX 完後進入RX mode,等待slave端發射RSSI返回值
			        ResetCmd(RXPOINT_RST);										
			        TIMEOUT = 1 ;
			        t0hrel   = 11200;                            
			        InitTimer0();
			        StrobeCmd(CMD_RX);                        //Entry RX MODE
			        RF_FLAG = 1;                              //Set RF Interrupt Flag
			        TR0 = 1;                                  //Enable Timer0 for counting RX Time out
			        TimeoutFlag = 0;                          //Reset RX Timeout Flag
			        timer = 0;                                //Reset Timer0 counter
			        while (RF_FLAG && (TimeoutFlag == 0));   //Wait for RX Receive done or RX Time out
		
			        if (TimeoutFlag)
			        {
			        	StrobeCmd(CMD_STBY);                    //Entry StandBy MODE
			        }
			        /* RX Receive done Process */
			        else
			        {					
						pair_cmd = A9101_ReadReg(RX_FIFO);
						Slave_rssi = A9101_ReadReg(RX_FIFO+1);
						link_OK++;		===================================================================
- Slave端 P3_2=1 
1. 進入RX Mode,等待TX端發射過來的ID Select Number "pair_cmd"=0x01 or 0x02
	 			for (i=0;i<1;i++)
				{
				    A9101_WriteReg(INTSW_REG, 0x80); 			//Fsync			
 			            SetCH (75);
				    RF_FLAG = 1;                              //Set RF Interrupt Flag                         
			            StrobeCmd(CMD_RX);                        //Entry RX MODE
			            while (RF_FLAG && (Pair_IO == 0));   		  //Wait for RX Receive					
					if((RF_FLAG == 0) && (Pair_IO == 0))
					{	
						Slave_rssi = A9101_ReadReg(RSSI_REG);
						RF_FLAG = 1; 
						A9101_WriteReg(INTSW_REG, 0x02);	//WTR 						
						while (RF_FLAG && (Pair_IO == 0));   		  //Wait for RX Receive done 
												
						link_OK++;
						pair_cmd = A9101_ReadReg(RX_FIFO);			2.回傳Slave端的RSSI值給Master端
A9101_WriteReg(TX_FIFO+1, Slave_rssi); Delay1ms(5); SetCH (75); A9101_WriteReg(INTSW_REG, 0x02); //WTR RF_FLAG = 1; StrobeCmd(CMD_TX); while (RF_FLAG);
3.若Slave端一直沒收到ID Select Number,則將link_OK =0,表示配對不成功
					else
					{
						link_OK = 0;					
					}		4. 如果link_OK >0 & RSSI值>RSSI門檻值,表示訊號正常,並判斷是要使用ID1 或 ID2進行通訊,並觸發P0_2反覆HIGH/LOW提示功能,直到P0_3拉HIGH後退出配對模式,回到語音傳輸模式
			if(link_OK && Slave_rssi > RSSI_threshold)
			{
				if(Pair1_IO == 0 && pair_cmd == 0x01)
					Pair1_OK = 1;
				else if(Pair2_IO == 0 && pair_cmd == 0x02)
					Pair2_OK = 1;
				else
					break;					
				while(Pair_IO == 0)	//pair ok, user can print message...
					P0_2 ^=1;===================================================================
配對完成後進入語音通話模式
while(DeviceLink(ScanMode(Pin_ModeSelect)));
Master介紹:
1. 開啟WTR中斷+CRC Data Filtering+FIFO長度定義成(0x63+1)=100Byte==>96 CodeC+4 Byte user CMD
/* Set RF */ EA = 1; //enable interrupt A9101_WriteReg ( INTSW_REG, 0x02 ); //enable WTR interrupt A9101_WriteReg ( RX_REG, A9101_CONFIGTABLE[RX_REG - CONFIG] | 0x80 ); //enable MSCRC A9101_WriteReg ( FIFO1_REG, 0x63 ); //FIFO Length = 96 bytes + 4byte cmd
2.開啟RSSI 檢測功能
/* Set RSSI */ A9101_WriteReg ( ADC_REG, 0xF2 ); //RRS=1, FSARS=0,RADC=1,HDM=1 ,RSM=3 A9101_WriteReg ( MODEC2_REG, A9101_CONFIGTABLE[MODEC2_REG - CONFIG] | 0x40 ); //ARRSI=1
3.初始化CodeC
InitCodec ( MASTER ); A9101_WriteReg ( CODEC_CODECTL, 0xB0 ); //ADC ON
4.判斷之前在A9101_Pair() 選中的ID Number ID1 或 ID2或廣播ID
if(Pair1_OK && (Pair1_IO == 0)) WriteID(Pair1_ID_Tab); else if(Pair2_OK && (Pair2_IO == 0)) WriteID(Pair2_ID_Tab); else WriteID(Broadcast_ID_Tab);
5.將ADC CodeC資料 & 自定義的0x01,0x02,0x03,0x04的字節加載到TX_FIFO Buffer裡
/* Write Packet to FIFO Buffer */ ResetCmd (TXPOINT_RST); //Reset RX FIFO Point X2X_DDP_MAMCPY(AU+TSL,CODECBUF[~TxIndex],TX_FIFO,96); //voice data A9101_WriteReg(TX_FIFO+96, 0x01); //control data A9101_WriteReg(TX_FIFO+97, 0x02); A9101_WriteReg(TX_FIFO+98, 0x03); A9101_WriteReg(TX_FIFO+99, 0x04);
6.連續在4個頻點上各打1包Tx Data
      for ( TXTimes = 0; TXTimes < 4; TXTimes++ )
      {
      	Delay100us(1);
      	
        /* Send TX */
        ERFINT = 1;                                 //Enable RF Interrupt
        SetCH (HoppingCH[TXTimes][channel_set]);	//Set RF Channel
        StrobeCmd ( CMD_TX );                       //Entry TX MODE
        RF_FLAG = 1;                                //Set RF Interrupt Flag
        while ( RF_FLAG );                          //Waiting RF Interrupt Trigger
	Read_RXIndex ( TXBufIndex );               //For Audio 對齊 0x1C=28,28/2 =14,14*125us=1.75ms,實測約1.769ms
        StrobeCmd ( CMD_PLL );                      //Entry PLL MODE
      }7. 更換下一組hopping table
channel_set++; if(channel_set == 4) channel_set = 0;
8.檢測當PTT Key 放開後退出語音模式
if ( ScanMode ( Pin_ModeSelect ) != MASTER || ScanMode ( Pin_ModeSelect ) == NonValid ) return 0;
9.如果按下Pair key時退出語音模式重新進入配對
			if(Pair_IO == 0)
			{
				A9101_WriteReg(CODEC_CODECTL, 0x00);       //ADC OFF
				return 0;
			}===================================================================
Slave端介紹:
1.開啟RSSI
2. 設定開啟WTR中斷+CRC Data Filtering+FIFO長度定義成(0x63+1)=100Byte==>96 CodeC+4 Byte user CMD
3.初始化CodeC & DAC ON & 靜音(Mute)
4.設定DAC 音量0x3C
/* Set RSSI */ A9101_WriteReg ( ADC_REG, 0xF2 ); //RRS=1, FSARS=0,RADC=1,HDM=1 ,RSM=3 A9101_WriteReg ( MODEC2_REG, A9101_CONFIGTABLE[MODEC2_REG - CONFIG] | 0x40 ); //ARRSI=1 /* Set RF */ EA = 1; //enable interrupt A9101_WriteReg ( INTSW_REG, 0x02 ); //enable WTR interrupt A9101_WriteReg ( RX_REG, A9101_CONFIGTABLE[RX_REG - CONFIG] | 0x80 ); //enable MSCRC A9101_WriteReg ( FIFO1_REG, 0x63 ); //FIFO Length = 96 bytes + 4byte cmd /* Set CODEC */ Empty = 1; //Set Empty Flag RxIndex = 0; TXBufIndex = 0; RXBufIndex = 0; InitCodec ( SLAVE ); A9101_WriteReg ( CODEC_CODECTL, 0x03 ); //DAC ON A9101_WriteReg ( CODEC_EFFCTL, 0x01 ); //Set Mute A9101_WriteReg(CODEC_VOL, VOLTest);
5.判斷選中的ID Number ID1 或 ID2 或廣播ID
6.若按下PTT KEY退出Slave,切到Master
7.如果按下Pair key時退出語音模式重新進入配對
			if(Pair1_OK && (Pair1_IO == 0))
			{
				if(broacast_flag)
					WriteID(Pair1_ID_Tab);
				else
					WriteID(Broadcast_ID_Tab);
			}
			else if(Pair2_OK && (Pair2_IO == 0))	
			{
				if(broacast_flag)
					WriteID(Pair2_ID_Tab);
				else
					WriteID(Broadcast_ID_Tab);
			}
			else
				WriteID(Broadcast_ID_Tab);
			broacast_flag ^=1;//broacast_flag=1
	  
			if ( ScanMode ( Pin_ModeSelect ) != SLAVE || ScanMode ( Pin_ModeSelect ) == NonValid )
				return 0;
	 
			if(Pair_IO == 0)
				return 0;8.分別在4個頻點上做接收,若接收超時重新進Standby
	for ( TXTimes = 0; TXTimes < sizeof 4; TXTimes++ )
	{
        if ( GetPacket )
          break;
        TIMEOUT = 1 ;
        t0hrel   = 22400;                            //2.03ms @16.384MHz
        InitTimer0();
        SetCH ( HoppingCH[TXTimes][channel_set]);    //Set RF Channel
        ResetCmd ( RXPOINT_RST );                    //Reset RX FIFO Point
        ERFINT = 1;                                  //Enable RF Interrupt
        StrobeCmd ( CMD_RX );                        //Entry RX MODE
        RF_FLAG = 1;                                 //Set RF Interrupt Flag
        TR0 = 1;                                     //Enable Timer0 for counting RX Time out
        TimeoutFlag = 0;                             //Reset RX Timeout Flag
        timer = 0;                                   //Reset Timer0 counter
        while ( RF_FLAG && ( TimeoutFlag == 0 ) );   //Wait for RX Receive done or RX Time out
        if ( TimeoutFlag )
        {
          ERFINT = 0;                                //Disable RF Interrupt
          StrobeCmd ( CMD_STBY );                    //Entry StandBy MODE
        }9.對其每個接收頻點的時間差=RXBufIndex
        /* RX Receive done Process */
        else
        {
	  Read_RXIndex ( RXBufIndex );            //for 對齊
          GetPacket = 1;
          switch ( TXTimes )
          {
          case 0:
					  RXBufIndex = 0x15 ;
            break;
          case 1:
					  RXBufIndex = 0x2B; 
            break;
          case 2:
					  RXBufIndex = 0x40 ;
            break;
          case 3:
					  RXBufIndex = 0x57 ;
            break;
          }
        }
      }10.若4個頻點都沒收到包,TXTimes == 3 就觸發一下P0_2 Low/High一回
        if ( TimeoutFlag )
        {
          ERFINT = 0;                                  //Disable RF Interrupt
          StrobeCmd ( CMD_STBY );                      //Entry StandBy MODE
          LossCnt ++;
					if(TXTimes == 3)
					{
						P0_2 = 0;
						P0_2 = 1;
						P0_2 = 0;				
					}
        }11. 掉包太多,跳出語音模式重新連接
if ( LossCnt > 10 ) return 0;
12.切換下一組hopping table & 解析CodeC資料與自定義資料寫入cmd[0],cmd[1],cmd[2],cmd[3]
channel_set++; if(channel_set == 4) channel_set = 0; while ( Empty ); //Wait for DAC Buffer Empty X2X_DDP_MAMCPY(AU+TSL,RX_FIFO,CODECBUF[~RxIndex],96); cmd[0]=A9101_ReadReg(RX_FIFO+96); cmd[1]=A9101_ReadReg(RX_FIFO+97); cmd[2]=A9101_ReadReg(RX_FIFO+98); cmd[3]=A9101_ReadReg(RX_FIFO+99);
13.當P1_6 拉LOW"進入靜音模式"
14.當P1_1拉LOW "+音量" / P1_0拉LOW "-音量"
      	      if ( LossCnt == 0 )
			{
				if(P1_6==0)
				{
					A9101_WriteReg ( CODEC_EFFCTL, 0x01 );//Mute
				}
				else
				{
					A9101_WriteReg ( CODEC_EFFCTL, 0x00 );//Disable Mute	        
					if(P1_1==0)
					{
						if(VOLTest>=0x3C)
							VOLTest=0x3C;
						else
							VOLTest=VOLTest+1;
						A9101_WriteReg(CODEC_VOL, VOLTest);
					}
					else if(P1_0==0)
					{
						if(VOLTest<=0x00)
							VOLTest=0;
						else
							VOLTest=VOLTest-1;
						A9101_WriteReg(CODEC_VOL, VOLTest);	
					}		       
					A9101_WriteReg ( CODEC_EFFCTL, 0x00 );//Disable Mute
				}
			}15.若有掉包則將DAC設成Mute,若按下PTT KEY退出Slave,切到Master,或是按下Pair Key時也可以跳出重新進入A9101_Pair();函數
			else
			{
				A9101_WriteReg ( CODEC_EFFCTL, 0x01 );//Mute
			}
			Empty = 1; //Set Empty Flag to avoid DAC Buffer doesn't finish the play
			if ( ScanMode ( Pin_ModeSelect ) != SLAVE || ScanMode ( Pin_ModeSelect ) == NonValid||Pair_IO == 0)
                            return 0;===================================================================
