RCカーモデルの円と時間の自動計算システム。 パート2プロトコルAMB20およびAMBRc

前の記事で、私はトランスポンダー、情報がトランスポンダーからデコーダーに無線で送信される方法について話しました。 今日は、トランスポンダーの数と時間に関する情報をコンピューターに転送する方法を説明します。 rctech.netで ここに集めた情報の一部

回路を組み立てましょう

そして、はんだ付けせずにブレッドボードに集めます: 必要なもの:1。 atmega16(私のデバイスではatmega32ですが、本質は変わりません)2。 USART 7.3728MHzのクォーツ。 (私のデバイスでは-16.59 MHz)3。 32 kHzでのクォーツ時間.4。 USB-RS232アダプター5。 LED、ボタン、抵抗器:MKファームウェアが入らないように、ブートローダーでいっぱいにします。 easyelectronics.ruに素晴らしい記事があります。 それはまさに私が使用するものです。 ブートローダーとメインプログラムの両方にLEDとボタンが必要ですデコーダーにはラップタイムをより正確に計算するための独自のクロックがありますが、さらに正確にするにはどうすればよいですか。 どのようにしても、トランスポンダー番号とループを通過した時間を送信するだけで、ブートローダーのLEDはブートローダーがロードされていることを示します。 そして、メインプログラムでは、彼は単純に点滅して、すべてが時計の順番に揃っていることを伝えます。ボタンを使用して、ループ上でのモデルの通過をシミュレートします。 原則として、任意のUSB-RS232アダプターが適しています。

AMB20

このプロトコルは、コントローラーの初期化と、トランスポンダーと時間に関する情報の送信という2つの部分に分けることができます。
時間カウント
32kHzクオーツのタイマーは1秒に1回中断されます。
interrupt [TIM2_OVF] void timer2_ovf_isr(void) { char i; if (++GlobalS==60) { if (++GlobalM==60) { GlobalH++; GlobalM=0; } GlobalS=0; } LED=!LED; }
      
      



すべてが明確でシンプルだと思います。
初期化
初期化中に、プログラムはCOMポートを開き、RTSを地上に置きます。 この信号の出力は、コントローラーINT0で停止します。 中断により、プログラム@ 00000001をコンピューターに送信し、コントローラーの時間をリセットします。
 delay_ms(100); printf("@00000001\r\n"); GlobalH=0; GlobalM=0; GlobalS=0; GlobalMs=0;
      
      



ループを通過するラベル
ラベルがループを通過したことをプログラムが理解するために、次の形式のレコードを送信する必要があります。
 Trans=1; MS=GlobalMs_Timer/2.56; H=GlobalH; M=GlobalM; S=GlobalS; printf("@%02u%02u%02u%02u%02u\r\n",Trans,H,M,S,MS);
      
      



例:@ 0102030405は、番号01のトランスポンダーが2時間3分4秒50ミリ秒ループを通過したことを意味します すべてが非常に簡単です。
プログラムコード
 /***************************************************** This program was produced by the CodeWizardAVR V2.05.0 Professional Automatic Program Generator © Copyright 1998-2010 Pavel Haiduc, HP InfoTech srl http://www.hpinfotech.com Project : Version : Date : 01.04.2013 Author : Company : Comments: Chip type : ATmega16 Program type : Application AVR Core Clock frequency: 7,372800 MHz Memory model : Small External RAM size : 0 Data Stack size : 256 *****************************************************/ #include <mega16.h> #ifndef RXB8 #define RXB8 1 #endif #ifndef TXB8 #define TXB8 0 #endif #ifndef UPE #define UPE 2 #endif #ifndef DOR #define DOR 3 #endif #ifndef FE #define FE 4 #endif #ifndef UDRE #define UDRE 5 #endif #ifndef RXC #define RXC 7 #endif #define FRAMING_ERROR (1<<FE) #define PARITY_ERROR (1<<UPE) #define DATA_OVERRUN (1<<DOR) #define DATA_REGISTER_EMPTY (1<<UDRE) #define RX_COMPLETE (1<<RXC) // USART Receiver buffer #define RX_BUFFER_SIZE 32 char rx_buffer[RX_BUFFER_SIZE]; #if RX_BUFFER_SIZE <= 256 unsigned char rx_wr_index,rx_rd_index,rx_counter; #else unsigned int rx_wr_index,rx_rd_index,rx_counter; #endif // This flag is set on USART Receiver buffer overflow bit rx_buffer_overflow; // USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) { char status,data; status=UCSRA; data=UDR; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { rx_buffer[rx_wr_index++]=data; #if RX_BUFFER_SIZE == 256 // special case for receiver buffer size=256 if (++rx_counter == 0) { #else if (rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0; if (++rx_counter == RX_BUFFER_SIZE) { rx_counter=0; #endif rx_buffer_overflow=1; } } } #ifndef _DEBUG_TERMINAL_IO_ // Get a character from the USART Receiver buffer #define _ALTERNATE_GETCHAR_ #pragma used+ char getchar(void) { char data; while (rx_counter==0); data=rx_buffer[rx_rd_index++]; #if RX_BUFFER_SIZE != 256 if (rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0; #endif #asm("cli") --rx_counter; #asm("sei") return data; } #pragma used- #endif // USART Transmitter buffer #define TX_BUFFER_SIZE 256 char tx_buffer[TX_BUFFER_SIZE]; #if TX_BUFFER_SIZE <= 256 unsigned char tx_wr_index,tx_rd_index,tx_counter; #else unsigned int tx_wr_index,tx_rd_index,tx_counter; #endif // USART Transmitter interrupt service routine interrupt [USART_TXC] void usart_tx_isr(void) { if (tx_counter) { --tx_counter; UDR=tx_buffer[tx_rd_index++]; } } #ifndef _DEBUG_TERMINAL_IO_ // Write a character to the USART Transmitter buffer #define _ALTERNATE_PUTCHAR_ #pragma used+ void putchar(char c) { if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0)) { tx_buffer[tx_wr_index++]=c; ++tx_counter; } else UDR=c; } #pragma used- #endif // Standard Input/Output functions #include <stdio.h> #include <delay.h> char GlobalH,GlobalM,GlobalS,GlobalMs; float TempFloat; #define GlobalMs_Timer TCNT2 #define LED PORTD.7 unsigned int Trans; // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { delay_ms(100); printf("@00000001\r\n"); GlobalH=0; GlobalM=0; GlobalS=0; GlobalMs=0; } interrupt [EXT_INT1] void ext_int1_isr(void) { char H,M,S,MS,Trans; Trans=1; MS=GlobalMs_Timer/2.56; H=GlobalH; M=GlobalM; S=GlobalS; printf("@%02u%02u%02u%02u%02u\r\n",Trans,H,M,S,MS); } interrupt [EXT_INT2] void ext_int2_isr(void) { } interrupt [TIM0_OVF] void timer0_ovf_isr(void) { } interrupt [TIM2_OVF] void timer2_ovf_isr(void) { char i; if (++GlobalS==60) { if (++GlobalM==60) { GlobalH++; GlobalM=0; } GlobalS=0; } LED=!LED; } void main(void) { PORTA=0x00; DDRA=0x00; PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x00; PORTD=0b1001100; DDRD=0x80; TCCR0=0x05; TCNT0=0x00; OCR0=0x00; ASSR=0x08; TCCR2=0x05; TCNT2=0x00; OCR2=0x00; GICR|=0xE0; MCUCR=0x0A; MCUCSR=0x00; GIFR=0xE0; TIMSK=0x41; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: On // USART Transmitter: On // USART Mode: Asynchronous // USART Baud Rate: 9600 UCSRA=0x00; UCSRB=0xD8; UCSRC=0x86; UBRRH=0x00; UBRRL=0x2F; #asm("sei") while (1) { } }
      
      



このプロトコルの欠点は明らかです-トランスポンダー番号は99以下です。別のプロトコルを検討してください。

AMBRC

このプロトコルには、MKからより多くのメモリが必要です。 理由は明らかです。 このプロトコルは、デコーダの初期化、ラベルの通過、デコーダのステータスの3つの部分に分けることができます。
初期化
プログラムは、次のテキストをデコーダーに送信します "?; 0; 0; 0;" バックスラッシュリターン(clcf)バイト-(0x0D、0x0A)。 このプログラムは、デコーダに興味深いものを送信しません。 したがって、入力にバイト0x0Aがあり、初期化フラグを設定している場合(フラグが必要な理由については後述します)。
 interrupt [USART_RXC] void usart_rx_isr(void) { char status,data; status=UCSRA; data=UDR; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { rx_buffer[rx_wr_index++]=data; if (data==0x0A) {TimeToInit=1;} //       #if RX_BUFFER_SIZE == 256 // special case for receiver buffer size=256 if (++rx_counter == 0) { #else if (rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0; if (++rx_counter == RX_BUFFER_SIZE) { rx_counter=0; #endif rx_buffer_overflow=1; } } }
      
      



しかし、メインループでは、以下を初期化します。
  if (TimeToInit) { putchar(1); printf("$\t%i\t7\t0\t1\t1\t",decoderid); putchar(0xF8); putchar(0xF9); printf("\r\n"); GlobalS=0; GlobalMs_Timer=0; sequence_number=0; TimeToInit=0; }
      
      



プロトコルの完全な説明は見つかりませんでしたが、一部しか見つかりませんでした。 COMポートのレコードは次のように送信されます。
01 24 09 31 30 30 09 37 09 30 09 31 09 31 09 F8 F9 0D 0A
ここでは、デコーダー番号は100です。記録は常にバイト(0x01)で始まります。 次は$記号です。 各値の間には符号タブ(0x09)があります。 すべてのエントリはキャリッジリターン(0x0D 0x0A)で終了します。 まあ、時間とsequence_numberをリセットする必要があることを忘れないでください。 sequence_numberは、区画ごとに増分される区画の番号です。
デコーダーの状態
4秒ごとにステータスを送信する必要があります。 パッケージビュー:
#100980 0 x06BA
バイトは次のようなものです。
01 23 09 31 30 30 09 31 30 32 38 09 30 09 78 39 42 39 46 0D 0A
ここでは、デコーダー番号、sequence_number、ある種のゼロ(理由はわかりません)およびチェックサムを確認できます。 チェックサムはputcharプロシージャで計算されます。
 void putchar(char c) { while (tx_counter == TX_BUFFER_SIZE); #asm("cli") crcwork = (crcTable[(crcwork >> 8) & 0xff] ^ (crcwork << 8) ^ c); //      if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0)) { tx_buffer[tx_wr_index++]=c; ++tx_counter; } else UDR=c; #asm("sei") }
      
      



crcTableテーブルは事前に計算され、ここにあります。
非表示のテキスト
flash unsigned int crcTable [256] = {0.4129.8258,12387,16516,20645,24774,28903,33032,37161,41290,45419,49548,53677,57806,61935,4657,528,12915,8786,21173 、17044.29431.25302.37689.33560.45947.41818.54205,50076,62463,58334,9314,13379,1056,5121,25830,29895,17572,21637,42346,46411,34088,38153,58862,62927 50604.54669.13907.9842.5649.1584.300423.26358.22165.18100.46939.42874.38681.34616.63455.59390.55197.51132.18628.22757.26758.300887.2112.6241.10242 、14371.51660.55789.59790.63919.35144.39273.43274.47403.23285.19156.31415.27286.6769.2640.14899.10770.56317.52188,64447,60318,39801,35672,47931,43802 27814.31879.19684.23749.11298.15363.3168.7233.60846.64911.52716.56781.44330.48395.36200,40265.32407.28342.24277,202,115891.11826.7761.3696.65439 61374.57309.53244.48923.44858.40793.36728.37256.33193.45514.41451.53516.49453.61774.57711.4224,161,12482,8419,20484,16421,28742,24679,33721,37784 、41979.46042.49981.54044.58239.62302.689.4752.8947.13010.16949.21012.25207.29270.46570.42443.38312.34185.62830.58703.54 572,50445,13538,9411,5280,1153,29798,25671,21540,17413,42971,47098,34713,38840,59231,63358,50973,55100,9939,14066,1681,5808,26199,30326,17941、 22068,55628,51565,63758,59695,39368,35305,47498,43435,22596,18533,30726,26663,6336,2273,14466,10403,52093,56156,60223,64286,35833,39896,43963,48026、 19061.23124.27191.31254.2801.6864.10931.14994.64814.60687.56684.52557.48554.44427,40424.36297.31782,27655,23652,19525,15522,11395,7392,3265,61215、 65342.53085.57212.44955.49082.36825,40952,28183,32310,20053,24180,11923,16050,3793,7920};
送信コード自体は次のようになります。
  if (TimeToSendAmbStatus) { sequence_number++; putchar(1); crcwork=0xFFFF; printf("#\t%i\t%i\t0\t",decoderid,sequence_number); printf("x%02X%02X\r\n",((crcwork>>8)&0xff),(crcwork&0xff)); TimeToSendAmbStatus=0; }
      
      



ここで、sequece_numberの増分方法を確認できます。 最初に0x01が送信され、次にcrcwork = 0xFFFFがリセットされます。 ヘルメットはパッケージの一部です。 同時に、チェックサムが考慮されます。 次のステップは、チェックサムとキャリッジリターンを送信することです。 したがって、4秒ごとに:
 interrupt [TIM2_OVF] void timer2_ovf_isr(void) { static char times; if (++times==4) { TimeToSendAmbStatus=1; times=0; } GlobalS++; LED=!LED; }
      
      



トランスポンダー番号と送信時間
これが困難の始まりです。 トランスポンダーの時間と数を変換し、USARTのバッファーに送信するのにかなり時間がかかります(どういうわけか約300ミリ秒でした)。そのため、割り込みでは何も直接送信せず、メインループに残します。 すべてが機能するためには、中間バッファーといくつかの変数を使用する必要があります。
 #define TranspondersCountMax 20 unsigned long int Transponders[TranspondersCountMax]; unsigned long int TranspondersTimeS[TranspondersCountMax]; unsigned int TranspondersTimeMS[TranspondersCountMax]; char TransponderNeedToSend, TranspondersCountInt, TranspondersCountMain;
      
      



ところで、バッファーは循環的で、これがバッファーを埋める方法です。
 interrupt [EXT_INT1] void ext_int1_isr(void) { unsigned long int S; unsigned int MS; MS=GlobalMs_Timer*3.90625; S=GlobalS; if (TransponderNeedToSend<TranspondersCountMax) { TransponderNeedToSend++; Transponders[TranspondersCountInt]=1234567; TranspondersTimeS[TranspondersCountInt]=S; TranspondersTimeMS[TranspondersCountInt]=MS; if (++TranspondersCountInt==TranspondersCountMax) TranspondersCountInt=0; } }
      
      



そしてメインループで:
 if (TransponderNeedToSend) { sequence_number++; putchar(1); crcwork=0xFFFF; printf("@\t%i\t%i\t%07lu\t%u.%03u\t130\t119\t2\t", decoderid, sequence_number, Transponders[TranspondersCountMain], TranspondersTimeS[TranspondersCountMain], TranspondersTimeMS[TranspondersCountMain]); //putchar('@'); //putchar(9); //printf("%i",decoderid); //putchar(9); //printf("%i",sequence_number); //putchar(9); //printf("%07lu",Trans); //putchar(9); //printf("%u.%03u",S,MS); //putchar(9); //printf("130"); //putchar(9); //printf("119"); //putchar(9); //printf("2"); //putchar(9); printf("x%02X%02X\r\n",((crcwork>>8)&0xff),(crcwork&0xff)); if (++TranspondersCountMain==TranspondersCountMax) TranspondersCountMain=0; TransponderNeedToSend--; }
      
      



「@ \ t%i \ t%i \ t%07lu \ t%u。%03u \ t130 \ t119 \ t2 \ t」の行で悪魔が足を折るので、コメントは同じことを言っています。 ユニットの送信、チェックサムの計算は、デコーダーステータスの送信と同じです。
@ 100 10 1234567 37.589 130119 2 xEB94
ご覧のとおり、すべてが非常に簡単です。

ラップカウントプログラムに関するいくつかの言葉

AMB serif互換のプログラムは数多くありますが、RCM Begginersを使用することを好みます。 それは無料で、ロシア語で非常に簡単です。 こちらからダウンロードできます。 ロシアでは、モデル作成者の間でRCM Ultimate(これは突然で高価です)が非常に人気があります。 AMB20とAMBRcは両方とも次のように構成されています。 他のプログラムは特に好きではありませんでした。

結論の代わりに

CodeVision Avrのソースとプロテウスのスキームはこちらにあります。



All Articles