Перейти к содержанию
    

Здравствуйте!

Сразу хочу извинится за дублирование темы, но вопрос как мне кажется относится к двум веткам: к радиопередатчикам и программированию.

 

Прошу помочь с вопросом программирования радиомодулей RFM12. Кто подключал и использовал, поделитесь инфой о "граблях". Бьюсь несколько дней, данные от модуля к модулю не передать. Запись в регистры проходит нормально (управляю тестовой частотой на CLK). Инициализацию делаю по документации на чип. Пытаюсь послать байт, приемник не принимает.

Заранее спасибо за советы!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если подключал к AVR пользуясь примером от производителя, то там ошибка в инициализации, кажется, приемника.

Ниже прикладываю проверенный пример работы взятый уже не помню где.

rfm12b.zip

rfm12b_and_avr__quick_start.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если подключал к AVR пользуясь примером от производителя, то там ошибка в инициализации, кажется, приемника.

Спасибо! Внимательно все изучаю. Если Вас не затруднит... вспомните точнее где ошибка. Перепробовал разные варианты инициализации.. все глухо..

:help: -----> :laughing:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В приложенной выше pdf-ке это место даже выделено на странице 4 во втором листинге

writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb,!ew,DC (bug was here)

а в родном документе от hoperf (приложил к посту ниже) на странице 20 в инициализации приемника есть такая строчка

 

RFXX_WRT_CMD(0x8239);//!er,!ebb,ET,ES,EX,!eb,!ew,DC ,

 

причем, в инициализации передатчика на странице 14 эта строчка такая же, что явно указывает на ошибку. В примере для PIC этой ошибки нет. Я ее обнаружил когда пример не заработал и начал проверять секцию инициализации модуля.

 

Тот пример, что я привел выше, запустился на макете сразу без всяких проблем. Попробуй с ним. Если будут проблемы, то надо проверять железо.

 

И еще. В примере от производителя используется программная реализация SPI. Проверял и с аппаратной в режиме mode0 (CPOL=0, CPHA=0). Частота должна быть не выше 10МГц(частота кварца на модуле)/4=2,5МГц. Я использовал 20/16=1,25МГц.

RF12B_code.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тот пример, что я привел выше, запустился на макете сразу без всяких проблем. Попробуй с ним. Если будут проблемы, то надо проверять железо.

Большое СПАСИБО! Все заработало. :a14:

Была путаница в инициализации и плюс к этому, не использовал выход IRQ.

Понадеялся на временные паузы между посылками.

В инициализации есть такая строчка:

writeCmd(0xCED4); //SYNC=2DD4ЃG

Непонятно, ведь такого регистра нет (CE)?!

Модуль у меня был на 433МГц.

Вот моя инициализация , может кому пригодится:

;приемник
                    send_rf12 $80D7
                    send_rf12 $8299
                    send_rf12 $A640
                    send_rf12 $C647
                    send_rf12 $94a0
                    send_rf12 $C2AC
                    send_rf12 $CA81
                    send_rf12 $Ced4                        
                    send_rf12 $C483
                    send_rf12 $9850
                    send_rf12 $CC17
                    send_rf12 $E000
                    send_rf12 $C800
                    send_rf12 $C040
;передатчик
                    send_rf12 $80D7
                    send_rf12 $8239
                    send_rf12 $a640
                    send_rf12 $c647
                    send_rf12 $94a0
                    send_rf12 $c2ac
                    send_rf12 $ca81
                    send_rf12 $CED4
                    send_rf12 $C483
                    send_rf12 $9850        
                    send_rf12 $CC17            
                    send_rf12 $E000            
                    send_rf12 $C800        
                    send_rf12 $C040

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В инициализации есть такая строчка:

writeCmd(0xCED4); //SYNC=2DD4

Непонятно, ведь такого регистра нет (CE)?!

 

Я так понял, что это "Synchron pattern Command" , описывается сразу после "FIFO and Reset Mode Command" . Командой writeCmd(0xCED4); задается, что в качестве нулевого байта будет использоваться 0xD4. Модуль может использовать в качестве синхронизирующей последовательности либо 1, либо 2 байта. Второй (Byte1) всегда равен 0x2D и включается битом sp в команде "FIFO and Reset Mode Command ", а первый (Byte0) можно задать самостоятельно как раз командой 0xCEхх.

 

Сам я это не проверял, использую рекомендованное значение, так что прокомментировать не могу.

 

И еще. Тут http://radio.delanet.ru/content/view/571/46/ можно скачать генераторы кода инициализации.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может мне кто поможет? Собрал два девайса MCU+RFM12BP, написал программу, конфигурации приемника/передатчика стянул отсюда но не работает. Не работает - это в смысле приемник не принимает (по RS232 приходят данные из "эфира" постоянно нули) Вот что сейчас есть:

1. Функции при работе непосредственно с RFM12BP

#define RF12_IRQ PINB.4

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define SCK 1   // SPI clock
#define SDO PINB.3   // SPI Data output (RFM12B side)	// приемник МЦУ
#define SDI 2   // SPI Data input (RFM12B side)		  // передатчик МЦУ
#define HI(x) PORTB |= (1<<(x))
#define LO(x) PORTB &= ~(1<<(x))
#define WAIT_NIRQ_LOW() while(PINB.4) delay_us(20)
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


uint8 RX_TX_STATE;   // 0-ни в каком состоянии
				 // 1-в состоянии приемника; 
				 // 2- в состоянии передатчика 

uint16 writeCmd(uint16 cmd) {
uint8 i;
uint16 recv;

recv = 0;
LO(SCK);
for(i=0; i<16; i++) {
	if(cmd & 0x8000) {
		HI(SDI);
		}
	else {
		LO(SDI);
		}
	HI(SCK);
	recv<<=1;
	if(SDO) {
		recv|=0x0001;
		}
	LO(SCK);
	cmd<<=1;
	}
return recv;
}   

void RF12_RX_Init_() {
writeCmd(0x80E7); //EL,EF,868band,12.0pF
writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb,!ew,DC
writeCmd(0xA640); //freq select
writeCmd(0xC647); //4.8kbps
writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
writeCmd(0xCED4); //SYNC=2DD4;
writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
writeCmd(0x9850); //!mp,90kHz,MAX OUT
writeCmd(0xCC17); //!OB1,!OB0, LPX,!ddy,DDIT,BW0
writeCmd(0xE000); //NOT USE
writeCmd(0xC800); //NOT USE
writeCmd(0xC040); //1.66MHz,2.2V
}

void RF12_TX_Init_() {
writeCmd(0x80E7); //EL,EF,868band,12.0pF
writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
writeCmd(0xA640); //frequency select
writeCmd(0xC647); //4.8kbps
writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
writeCmd(0xCED4); //SYNC=2DD4ЃG
writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
writeCmd(0x9850); //!mp,90kHz,MAX OUT
writeCmd(0xCC17); //OB1ЃCOB0, LPX,ЃIddyЃCDDITЃCBW0
writeCmd(0xE000); //NOT USE
writeCmd(0xC800); //NOT USE
writeCmd(0xC040); //1.66MHz,2.2V
} 

void FIFOReset_() {
writeCmd(0xCA81);
writeCmd(0xCA83);
}

void RF12_SEND_(uint8 DATA) {
WAIT_NIRQ_LOW();
writeCmd(0xB800 + DATA);
}  

uint8 RF12_RECV_(void) {
uint16 data;  
WAIT_NIRQ_LOW();	
writeCmd(0x0000);
data = writeCmd(0xB000);
return (data & 0x00FF);
}

 

2. По RS232 я задаю кто будет приёмником а кто передатчиком. Вот краткий пример:

#define RX_ON  PORTB |= (1<<7)
#define RX_OFF PORTB &= (uint8) ~(1<<7)

#define TX_ON  PORTB |= (1<<6)
#define TX_OFF PORTB &= (uint8) ~(1<<6)

...........................

case (7): {
					RX_TX_STATE=2; // Задаем состояние передатчика
					RX_OFF;
					TX_ON;
					RF12_TX_Init_(); 
					} break; 
				case (8): {						  
					RX_TX_STATE=1; // Задаем состояние приемника
					TX_OFF;
					RX_ON;
					RF12_RX_Init_();				   
					}  break;
.........................

 

3. ВОт что делаю в основном цикле main

while (1) {		  
	if(RX_TX_STATE==2) {   // Если в состоянии передатчика
		//RF12_SEND(0xAD);
		writeCmd(0x0000);
		RF12_SEND_(0xAA); // PREAMBLE
		RF12_SEND_(0xAA);
		RF12_SEND_(0xAA);
		RF12_SEND_(0x2D); // SYNC
		RF12_SEND_(0xD4);
		for(i=0; i<16; i++)
			RF12_SEND_(0x30+i);
		RF12_SEND_(0xAA); // DUMMY BYTES
		RF12_SEND_(0xAA);
		RF12_SEND_(0xAA); 

		delay_ms(50);
		}
	else if (RX_TX_STATE==1) { // Если в состоянии приемника
		for (i=0; i<16; i++) {
			data = RF12_RECV_();
			USART_Transmit_Package((1<<5) | 2,data,0);
			delay_ms(10);
			}
		FIFOReset_();

		delay_ms(100);
		}  
	else if (RX_TX_STATE==0) {

		}		  

	}

 

Парюсь уже третий день и понять не могу что неправильно. Схемотехника проверена - все соединения прозвонены. Помогите плиз кто на этом уже собаку сьел!!! От безысходности уже взял фукцию долбить SPI "вручную" нежели аппаратными средствами SPI.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Скорее всего ошибка в функции приема:

 

uint8 RF12_RECV_(void) {
uint16 data;  
WAIT_NIRQ_LOW();	
writeCmd(0x0000);
data = writeCmd(0xB000);
return (data & 0x00FF);
}

 

Потому что WAIT_NIRQ_LOW(); используется только при передаче. В документе, который я приложил во втором сообщении в этой тебе как раз это и описано на странице 6 сверху. Если очень сильно нужно работать с приемником по прерываниям, то надо использовать вывод FFIT/DCLK (сам не проверял, потому что нашел другой более подходящий для меня способ, о котором ниже). Если не изменяет память, то у меня тоже шли постоянные 0x00 когда я делал с WAIT_NIRQ_LOW(); В том же документе для приемника приведен такой код:

 

unsigned char rfRecv() {
unsigned int data;
while(1) 
{
data = writeCmd(0x0000);
if ( (data&0x8000) ) {
data = writeCmd(0xB000);
return (data&0x00FF);
}
}
}

 

Объясню это словами: для того что бы знать принят байт или нет, в модуль надо писать пустое слово 0x0000, и смотреть установлен ли в принятом слове старший байт. Но мне этот метод не понравился из-за достаточно большой длительности. Однако, если учесть, что радиомодуль передает данные старшим битом вперед, то можно просто смотреть на уровень сигнала на ножке MISO микроконтроллера предварительно выбрав модуль и опустив уровень на ножке MOSI. (Этот метод показан на странице 25 родного даташита на микросхему RF12B). Кроме того я таким образом еще и проверял наличие данных для приема в основном цикле основной программы: опускаем CS, опускаем MOSI, если на ножке MISO высокий уровень, то можно принимать данные.

 

Прилагаю свой вариант работы с модулем взятый из своего проекта. Код точно рабочий. Если где поудалял из файлов нужные #define, пиши, добавлю.

 

Хотя повторюсь, что если требуется максимальная скорость обнаружения принятых данных, то нужно выделить для прерываний от приемника отдельный вывод.

RFM12B.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

DiMomite

Спасибо что откликнулись. На счет

while(1) {...}

в функции приемника - мне это не понравилось т.к. если ничего не приходит то контроллер уходит в ступор. А чтобы не уходил надо на Прием выделять некоторое кол-во времени - например заводить переменную i и считать её кол-во. Вот например:

uint8 RF12_RECV_(void) {
    uint16 data;  
    uint16 i; 
    i=0;
    while(1) {    
        data = writeCmd(0x0000);
        i++;  
        if ( (data&0x8000) ) {
            data = writeCmd(0xB000);
            return (data & 0x00FF);
            }
        else if (i==0xFFFF) return(0);
        }
    }

 

У меня еще был CS притянут к GND через 10к. Кинул CS на МЦУ чтобы долбить вручную.

В общем даже если убрать из приемника WAIT_NIRQ_LOW(); (в чем вы абсолютно правы - это нужно только для передатчика) и сделать CS то результат всё равно тот же - приёма нет. Ох видать либо где-то глупая ошибка либо один из RFM12BP битый.

 

Кстати чтобы исключить последнее как можно точно проверить живой там кристалл или нет? Осциллографа нет - так бы по управлял выходной частотой модуля меняя делитель.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще что интересно, если в "чистый" (неконфигурируемый) RFM12BP отослать 0x0000 то вывод IRQ становиться в 1. К чему бы это?

Изменено пользователем Halfback

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И еще. Тут http://radio.delanet.ru/content/view/571/46/ можно скачать генераторы кода инициализации.

 

А вот тут говорится о ошибках в доках производителя и дается исправленный вариант.

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добился всё-таки обмена по радиоканалу.

 

Но всё же остается вопрос по регистру Receiver Control Command . Как использовать битик Р16 (Interrupt input /VDI)???

В даташите что-то внятного по VDI либо Interrupt input не нашел. И не понятно что в этом случае является для модуля RFM12BP входом а что выходом.

Идея в том что по приходу байта хочу вызывать обработчик прерывания.

 

Может кто разьяснить? Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я также пытаюсь связать два модуля RFM12B, но пока безуспешно. Приемник получает только (0хFF)

 

Привожу код приемника:

#define EnableInterrupts()   _SEI();
#define DisableInterrupts()  _CLI();

#define MAIN_FREQ 7372800

#define SCK 5   // SPI clock					  B
#define SDO 5   // SPI Data output (RFM12B side)  D
#define SDI 3   // SPI Data input (RFM12B side)   B
#define CS  4   // SPI SS (chip select)		   D

#define NIRQ 3  // (PORTD)
#define WAIT_NIRQ_LOW() while(PIND&(1<<NIRQ))

//#define HI(x) PORTB |= (1<<(x))
//#define LO(x) PORTB &= ~(1<<(x))


#define HI_SCK PORTB |= (1<<5)
#define LO_SCK PORTB &= ~(1<<5)

#define HI_SDI PORTB |= (1<<3)
#define LO_SDI PORTB &= ~(1<<3)

#define HI_CS PORTD |= (1<<4)
#define LO_CS PORTD &= ~(1<<4)

#define LED 4		   //  B
#define LED_OFF() PORTB &= ~(1<<LED)
#define LED_ON() PORTB |= (1<<LED)


typedef unsigned char byte;

#include <ina90.h>
#include <iom48.h>

void rsInit(void) {  
 UBRR0L = 3;//(MAIN_FREQ / (16 * baud)) - 1;   //115200
 UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);  // 8N1
 UCSR0B = (1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0);	// enable tx and rx and interrupts
}

void rsSend(unsigned char data) {
 while( !(UCSR0A & (1<<UDRE0)));
 UDR0 = data;
}
/*unsigned char rsRecv() {
 while( !(UCSR0A & (1<<RXC0)));
 return UDR0;
}*/



void HardwareInit() {

 PORTB=0x00;
 DDRB=0x00;
 PORTC=0x00;  
 DDRC=0x00;
 PORTD=0x00;
 DDRD=0x00; 

 HI_CS;
 HI_SDI;
 LO_SCK;
 DDRB = (1<<SDI) | (1<<SCK)|(1<<LED);
 DDRD = (1<<CS); 

	// WDT prescaler
__watchdog_reset();
// Start timed equence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Set new prescaler(time-out) value = 64K cycles (~0.25 s) 
WDTCSR = (1<<WDE) | (1<<WDP2) | (1<<WDP0);

}

void ClearWDT(void){
_WDR();
}

unsigned int writeCmd(unsigned int cmd) {
 unsigned char i;
 unsigned int recv;
 recv = 0;
 LO_SCK;
 LO_CS;
 for(i=0; i<16; i++) {
if(cmd&0x8000) HI_SDI;
else LO_SDI;	
HI_SCK;	
recv<<=1;
if( PIND&(1<<SDO) ) recv|=0x0001;
LO_SCK;
cmd<<=1;
 }
 HI_CS;
 return recv;
}

void FIFOReset() {
 writeCmd(0xCA81);
 writeCmd(0xCA83);
}



/*
void waitForData() {
 unsigned int status;
 while(1) {
status = writeCmd(0x0000);
if ( (status&0x8000) ) {
  return;
}
 }
}
*/
void rfInit() {
 writeCmd(0x80D7); //EL,EF,433band,12.0pF 
 writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb,!ew,DC
 writeCmd(0xA640); //freq select
 writeCmd(0xC647); //4.8kbps
 writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
 writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
 writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
 writeCmd(0xCED4); //SYNC=2DD4;
 writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
 writeCmd(0x9850); //!mp,90kHz,MAX OUT
 writeCmd(0xCC17); //!OB1,!OB0, LPX,!ddy,DDIT,BW0
 writeCmd(0xE000); //NOT USE
 writeCmd(0xC800); //NOT USE
 writeCmd(0xC040); //1.66MHz,2.2V
}

/*
unsigned char rfRecv() {
 unsigned int data;
 writeCmd(0x0000);
 data = writeCmd(0xB000);
 return (data&0x00FF);
}
*/

unsigned char rfRecv() {
 unsigned int data;
 while(1) {
data = writeCmd(0x0000);
if ( (data&0x8000) ) {
data = writeCmd(0xB000);
return (data&0x00FF);
}
ClearWDT();
 }  
}

int main(void) {
 unsigned char data, i;  
 HardwareInit();
 rfInit();  
 rsInit();
 FIFOReset();
 while(1) {
  LED_ON();
  //waitForData();
  for (i=0; i<16; i++) {
	data=0;
	data = rfRecv();
	//if(data==0x00A1)LED_ON();
	rsSend(data);
  }
  FIFOReset();
  LED_OFF();
  ClearWDT();
 }  
}

 

и передатчика:

 

#define EnableInterrupts()   _SEI();
#define DisableInterrupts()  _CLI();

#define SCK 5   // SPI clock					  B
#define SDO 5   // SPI Data output (RFM12B side)  D
#define SDI 3   // SPI Data input (RFM12B side)   B
#define CS  4   // SPI SS (chip select)		   D
#define NIRQ 3  // (PORTD)

//#define HI(x) PORTB |= (1<<(x))
//#define LO(x) PORTB &= ~(1<<(x))


#define HI_SCK PORTB |= (1<<5)
#define LO_SCK PORTB &= ~(1<<5)

#define HI_SDI PORTB |= (1<<3)
#define LO_SDI PORTB &= ~(1<<3)

#define HI_CS PORTD |= (1<<4)
#define LO_CS PORTD &= ~(1<<4)


#define WAIT_NIRQ_LOW() while(PIND&(1<<NIRQ))

#define LED 4		   //  B
#define LED_OFF() PORTB &= ~(1<<LED)
#define LED_ON() PORTB |= (1<<LED)


typedef unsigned char byte;

#include <ina90.h>
#include <iom48.h>



void HardwareInit() {

 PORTB=0x00;
 DDRB=0x00;
 PORTC=0x00;  
 DDRC=0x00;
 PORTD=0x00;
 DDRD=0x00; 

 HI_CS;
 HI_SDI;
 LO_SCK;
 DDRB = (1<<SDI) | (1<<SCK) | (1<<LED);
 DDRD = (1<<CS); 


	// WDT prescaler
__watchdog_reset();
// Start timed equence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Set new prescaler(time-out) value = 64K cycles (~0.25 s) 
WDTCSR = (1<<WDE) | (1<<WDP2) | (1<<WDP0);

}


void ClearWDT(void){
_WDR();
}

unsigned int writeCmd(unsigned int cmd) {
 unsigned char i;
 unsigned int recv;
 recv = 0;
 LO_SCK;
 LO_CS;
 for(i=0; i<16; i++) {
if(cmd&0x8000) HI_SDI; else LO_SDI;
HI_SCK;
recv<<=1;
if( PIND&(1<<SDO) ) recv|=0x0001;
LO_SCK;
cmd<<=1;
 }
 HI_CS;
 return recv;
}

void rfInit() {
 writeCmd(0x80D7); //EL,EF,433band,12.0pF 
 writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
 writeCmd(0xA640); //frequency select
 writeCmd(0xC647); //4.8kbps
 writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
 writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
 writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
 writeCmd(0xCED4); //SYNC=2DD4�G
 writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
 writeCmd(0x9850); //!mp,90kHz,MAX OUT
 writeCmd(0xCC17); //OB1�COB0, LPX,�Iddy�CDDIT�CBW0
 writeCmd(0xE000); //NOT USE
 writeCmd(0xC800); //NOT USE
 writeCmd(0xC040); //1.66MHz,2.2V
}

void rfSend(unsigned char data){
 //WAIT_NIRQ_LOW();
 while(PIND&(1<<NIRQ))ClearWDT();
 writeCmd(0xB800 + data);
}

int main() {
 volatile unsigned int i,j;
 asm("cli");
 for(i=0;i<1000;i++)ClearWDT();
 for(j=0;j<123;j++); ClearWDT();
 ClearWDT();
 HardwareInit();  
 rfInit();
 while(1){
LED_ON();
writeCmd(0x0000);
rfSend(0xAA); // PREAMBLE
rfSend(0xAA);
rfSend(0xAA);
rfSend(0x2D); // SYNC
rfSend(0xD4);
for(i=0; i<16; i++) {
  rfSend(0x30+i);
}
rfSend(0xAA); // DUMMY BYTES
rfSend(0xAA);
rfSend(0xAA);
LED_OFF();

for(i=0; i<10000; i++)ClearWDT();
for(j=0; j<123; j++);  ClearWDT();  
 }
}

 

Код взял из примера, вроде ничего не напутал, проверил схему, подключения, но не нашел где собака порылась. Может кому бросится в глаза где я накуралесил, буду очень признателен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Расскажу об опыте применения модуля si4421 (аналог rf12).

Написано внизу много но всё это фрагменты программы реально работающего устройства.

 

Всё начинается с инициализации. При работе по прерываниям желательно дождаться пока вывод прерываний не установится в 1.

Для этого достаточно читать регистр статуса пока не модуль не "отпустит"

Пример инициализации (если в настройке регистра бит не указан то он не испрользуется, сами названия как в документации)

Исключения составляют регистры FREQSET_CMD и DATARATE_CMD - для них я отдельно расчитываю константы (как - написано в документации).

 

///////////////////////////////////////
void si4421_init(void)
{
  delay_ms(100);
  while(!(RF12_PIN&(1<<nIRQ))) SPIWriteWord(0x0000);
  
  SPIWriteWord(Si4421_CONFIGSET_CMD|(1<<bf0)|(1<<x3));//EL,EF,433band,12.5pF //0x80E7 
  SPIWriteWord(Si4421_POWERMAN_CMD|(1<<es)|(1<<ex)|(1<<dc)); //er,!ebb,ET,ES,EX,!eb,!ew,DC //SPIWriteWord(Si4421_POWERMAN_CMD|(1<<et)|(1<<es)|(1<<ex)|(1<<dc)); //er,!ebb,ET,ES,EX,!eb,!ew,DC 
  SPIWriteWord(Si4421_FREQSET_CMD + FrequencyTable[default_chanel&0x0f]); 
  SPIWriteWord(Si4421_DATARATE_CMD); //datarate
  SPIWriteWord(Si4421_RECEIVERCNT_CMD|(1<<p16)|(1<<i2)|(1<<i1)); //VDI,FAST,64kHz,0dBm,-103dBm
  SPIWriteWord(Si4421_DATAFILTER_CMD|(1<<al)|(1<<f_2)); //AL,!ml,DIG,DQD4
  SPIWriteWord(Si4421_FIFO_RESET_CMD|(1<<fi3)/*|(1<<dr)*/); //FIFO8,SYNC,!ff,DR
  SPIWriteWord(Si4421_SYNCPATT_CMD); //SYNC=2DD4;
  SPIWriteWord(Si4421_AFC_CMD|(1<<a1)|(1<<oe)|(1<<en)); //@PWR,NO RSTRIC,!st,!fi,OE,EN 
  SPIWriteWord(Si4421_TXCONFIG_CMD|(1<<m1)); //!mp,45kHz,MAX OUT
  SPIWriteWord(Si4421_PLLSET_CMD|(1<<dly)|(1<<bw0)); //!OB1,!OB0, LPX,!ddy,DDIT,!BW0
  SPIWriteWord(Si4421_WTC_CMD);//NOT USE
  SPIWriteWord(Si4421_LOWDUTYCCL_CMD);//NOT USE
  SPIWriteWord(Si4421_LBD_CMD);//2,25 V   1 MHz
}
///////////////////////////////////////

 

После инициализации модуль готов быть включённым на приём или передачу

///////////////////////////////////////
void si4421_on_tx(void)
{
  SPIWriteWord(Si4421_CONFIGSET_CMD|(1<<el)|(1<<bf0)|(1<<x3));//EL,EF,433band,12.5pF //0x80E7 
  SPIWriteWord(Si4421_POWERMAN_CMD|(1<<et)|(1<<es)|(1<<ex)|(1<<dc)); //er,!ebb,ET,ES,EX,!eb,!ew,DC 
}
///////////////////////////////////////

///////////////////////////////////////
void si4421_on_rx(void)
{
  SPIWriteWord(Si4421_CONFIGSET_CMD|(1<<ef)|(1<<bf0)|(1<<x3));//EL,EF,433band,12.5pF //0x80E7 
  SPIWriteWord(Si4421_POWERMAN_CMD|(1<<er)|(1<<es)|(1<<ex)|(1<<dc)); //er,!ebb,ET,ES,EX,!eb,!ew,DC 
  si4421_fifo_reset();
}
///////////////////////////////////////

 

При включении на приём я дополнительно сбрасываю фифо чтобы она была готова к приёму данных

///////////////////////////////
void si4421_fifo_reset() {
  SPIWriteWord(Si4421_FIFO_RESET_CMD|(1<<fi3)/*|(1<<dr)*/);
  SPIWriteWord(Si4421_FIFO_RESET_CMD|(1<<fi3)|(1<<ff)/*|(1<<dr)*/);
}
//////////////////////////////////////

 

Таким образом после влючения питания выполняем такие действия

 

void main(void)
{
//инициализируем мк
...................................

//инициализация внешнего прерывания
............................................................

//инициализируем rf12
si4421_init();
si4421_on_tx(); //или si4421_on_rx();

while(1)
{
    //вечный цикл
    //также сдесь можно вставить опрос регистра статуса чтобы не городить работу по прерываниям
    if(rf12_flag)
    {
      Si4421_handler();
      rf12_flag = 0;
     }
}

}

 

Этого достаточно чтобы модуль заработал как положено.

Теперь собственно по приёму/передаче данных

 

У меня rf12 висит на внешнем прерывании настроенном на срабатывание по заднему фронту

В прерывании просто вставляется флаг rf12_flag, обработка идёт в основном цикле

 

Действия при приёме данных

/////////////////////////////////////////////
inline unsigned int si4421_read_status(void){return (SPIWriteWord(0x0000));}
/////////////////////////////////////////////

/////////////////////////////////////////////
unsigned char si4421_read_fifo()
{
  unsigned int data;
  data = SPIWriteWord(0xB000);
  return ( (unsigned char) (data&0x00ff) );
}
/////////////////////////////////////////////

#define FFIT 0x8000 //fifo receive preprogrammed number of bits

/////////////////////////////////////////////
void Si4421_handler(void)
{
  unsigned int status;
  unsigned char data;

  //обязательно читаем статус чтобы сбросить источник прерываний
  status = si4421_read_status();
  
  //если в фифо есть данные то считываем
  if(status&FFIT) 
    {
        data = si4421_read_fifo();

        //делаем с данными что хотим например отправляем в уарт
       putchar(data);
    }
}
/////////////////////////////////////////////

 

Действия при передаче также просты

 

///////////////////////////////////////
void si4421_write_tx(unsigned char byte)
{
  SPIWriteWord(0xB800 | byte);
}
///////////////////////////////////////

#define RGIT 0x8000 //tx reg ready to receive new byte for transmitt

/////////////////////////////////////////////
void Si4421_handler(void)
{
  unsigned int status;
  unsigned char data;

  //обязательно читаем статус чтобы сбросить источник прерываний
  status = si4421_read_status();
  
  //если передающий регистр готов к отправке данных то ложим в него байт
  if(status&RGIT) 
    {
        si4421_write_tx(my_data_for_transmitt);
    }
}
/////////////////////////////////////////////

 

 

У меня лично модуль работает и на приём и на передачу (не одновременно а когда нет данных данных для передачи он всё время в режиме приёма,

когда есть данные то переключается на передачу, передаёт и снова переходит в режим приёма). Всё построено на прерывании от модуля, данные для передачи буферизируются в уарт_фифо.

 

При передаче данных данных обязательно необходимо передавать такую последовательность

0xAA; 0xAA; 0xAA; 0x2D; 0xD4; свои данные; 0xAA; 0xAA; 0xAA;

 

Первые три 0xAA для синхронизации передатчика с приёмником

0x2D; 0xD4; синхропоследовательность после которой фифо в модуле начнёт генерировать прерывания по приёму данных

Последние три 0xAA нужны чтобы последние байты данных гарантировано передались в эфир а не остались в передающем буффере модуля.

 

Команда сброса фифо позволяет прервать текущий приём и заново фифо будет заполнятся только после приёма новой синхропоследовательности.

 

Если нет желания цеплять модуль на прерывание можно постоянно мониторить регистр статуса чтобы знать что с модулем происходит (когда заполнится фифо, когда передающий регистр будет пуст).

 

Два абсолютно одинаково настроенных модуля но один включённый на приём а второй на передачу будут гарантированно иметь связь друг с другом если передавать последовательность данных как указано выше и соблюсти правило - или в прерывании или остоянно опрашивая регист статуса мониторить готовность передающего регистра или наличие данных в приёмной фифо. Для надёжности в приёмнике после принятия стоповой комбинации (например байт 0x0D) желательно сбрасывать фифо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за помощь, все заработало!!!

Но к стыду своему добавлю, что причина была в железе -взял платку с другого устройства и не увидел поддяжку с SDO на питание.

Но есть в этом и плюсы - разобрался с модулями :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...