LINUX.ORG.RU

Программный ИК-передатчик


0

1

Имеется FTDI232, к ней подключен ИК-светодиод (с транзисторным ключом для усиления). Требуется передавать данные, на принимающей стороне AVR с ИК-приёмником TSOP1736. Проблема в том, что пока оно особо не работает. С AVR разберусь как-нибудь сам, а вот программная модуляция частоты хз как работает.

#include <stdio.h>
#include <stdlib.h> 
#include <ftdi.h>

#define LED 0x08

#define FREQ (36000 * 2)
#define SPEED 1200
#define BIT_LENGTH (FREQ / SPEED)

struct ftdi_context ctx;

void send_message(unsigned char *data, size_t count) {
	size_t buf_size = BIT_LENGTH * count * 8;
	unsigned char *buf = malloc(buf_size);
	size_t i, k = 0;
	for (i = 0; i < count; i++) {
		unsigned char byte = data[i];
		unsigned char j;
		for (j = 0; j < 8; j++) {
			int n;
			if (byte & (1 << (7 - j))) {
				for (n = 0; n < (BIT_LENGTH / 4); n++) {
					buf[k] = LED;
					k++;
					buf[k] = 0;
					k++;
				}
				for (n = 0; n < (BIT_LENGTH / 4); n++) {
					buf[k] = 0;
					k++;
					buf[k] = 0;
					k++;
				}
			} else {
				for (n = 0; n < (BIT_LENGTH / 4); n++) {
					buf[k] = 0;
					k++;
					buf[k] = 0;
					k++;
				}
				for (n = 0; n < (BIT_LENGTH / 4); n++) {
					buf[k] = LED;
					k++;
					buf[k] = 0;
					k++;
				}
			}
		}
	}
	printf("\n");
	ftdi_write_data(&ctx, buf, buf_size);
	free(buf);
}

int main(int argc, char *argv[]) {
	ftdi_init(&ctx);
	if(ftdi_usb_open(&ctx, 0x0403, 0x6001) < 0) {
		printf("Can't open FTDI device!\n");
		return 1;
	}
	ftdi_enable_bitbang(&ctx, LED);
	ftdi_set_baudrate(&ctx, FREQ / 16);
	char msg[] = {0xFF};
	send_message(msg, sizeof(msg));
	return 0;
}

Я всё правильно делаю или нет? Частота несущей 36 КГц. Аппаратная часть передатчика точно работает - светодиод мигает (видно с помощью камеры мобильного телефона).

★★★★★

Проконтролируй осциллографом. Есть осциллограф?

И еще. У FTDI какая-то ошибка была в чипе, касасающаяся BitBang mode. Надо учесть. Вот errata на этот счет на четвертой страничке. Посмотри, где этот баг встречается. касается ли он тебя.

http://www.ftdichip.com/Support/Documents/TechnicalNotes/TN_120_FT232R Errata...

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)

И какой алгоритм модуляции? А то я не пойму, так как ты модулируешь и «1» (первая часть if), и «0» (часть else). А надо что-то одно, по-моему.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

1 у меня это когда сначала сигнал есть, а потом нет, а 0 это когда сначала сигнала нет, а потом он есть.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от Zubok

Так... частота точно правильная, потому что датчик таки срабатывает и вызывает прерывание. Но только вот принимаются одни нули, значит я напутал либо с алгоритмом модуляции, либо с алгоритмом демодуляции.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

Так... частота точно правильная, потому что датчик таки срабатывает и вызывает прерывание. Но только вот принимаются одни нули, значит я напутал либо с алгоритмом модуляции, либо с алгоритмом демодуляции.

Вполне может быть. Я так понимаю, что ты кодируешь не биты, а переходы от 0 к 1, и от 1 к 0, так? NRZ по сути.

Осциллографа нет?

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)

да, не по делу, но лучше убрать повторы кода:

size_t write_real_bit(unsigned char* buf, size_t k, unsigned char value)
{
	int n;
	for (n = 0; n < (BIT_LENGTH / 4); n++) {
		buf[k] = value;
		k++;
		buf[k] = 0;
		k++;
	}
	return k
}
size_t write_bit(unsigned char* buf, size_t k, unsigned char bit)
{
	k =    write_real_bit(buf,k,(bit!=0)?LED:0);
	return write_real_bit(buf,k,(bit!=0)?0:LED);
}
void send_message(unsigned char *data, size_t count) {
	size_t buf_size = BIT_LENGTH * count * 8;
	unsigned char *buf = malloc(buf_size);
	size_t i, k = 0;
	for (i = 0; i < count; i++) {
		unsigned char byte = data[i];
		unsigned char j;
		for (j = 0; j < 8; j++)
			k = write_bit(buf,k,(byte & (1 << (7 - j))));
	}
	printf("\n");
	ftdi_write_data(&ctx, buf, buf_size);
	free(buf);
}

anonymous
()
Ответ на: комментарий от Zubok

Да, так. Осциллографа нет. Проблема, вероятно, на стороне AVR.

unsigned int rx_buffer;
unsigned char rx_count;

ISR(INT0_vect) {
	unsigned char half_bit;
	if (PIND & _BV(2) == 0) {
		half_bit = 1;
	} else {
 		half_bit = 0;
	}
	rx_buffer = rx_buffer << 1;
	rx_buffer |= half_bit;
	rx_count++;
	if (rx_count == 16) {
		... тут я вывожу rx_buffer ...
		rx_count = 0;
	}
}

...
GIMSK |= _BV(INT0);
MCUCR &= ~_BV(ISC01);
MCUCR |= _BV(ISC00);

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

И... приходит 16 бит (я ещё не делаю декодировку в нормальные биты и их в 2 раза больше), то есть INT0 вызывается 16 раз. И это хорошо и правильно. Однако, каждый раз с PIND почему-то читается единица (что значит, что сигнала нет). С другой стороны, если бы состояние вывода не становилось иногда нулевым, не было бы изменения уровня и INT0 не случился бы. Так что проблема в программе.

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 3)
Ответ на: комментарий от KivApple

Да, так. Осциллографа нет. Проблема, вероятно, на стороне AVR.

Сейчас гляну. У меня тут есть FTDI. Код твой скомпилю и осциллографом ткнусь.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Это не NRZ, а манчестерское кодирование.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

Но стоп. Я, наверное, не разглядел. Там же модуляция 36 кГц должна быть. Что-то я не заметил, похоже, ее. Или ее нет вообще. Сейчас еще раз гляну

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

Попробовал вот такой алгоритм (скорость - 1000 бит/сек):

ISR(INT0_vect) {
	GIMSK &= ~_BV(INT0);
	TCNT2 = 255 - 250;
	TCCR2 = _BV(CS22); // div 64
	rx_buffer = 1;
	rx_count = 1;
}

ISR(TIMER2_OVF_vect) {
	TCNT2 = 255 - 250;
	rx_buffer = rx_buffer << 1;
	rx_buffer = rx_buffer | ((PIND & _BV(2) == 0) ? 1 : 0);
	rx_count++;
	if (rx_count == 8) {
		TCCR2 = 0;
		GIMSK |= _BV(INT0);
		if (rx_buffer == 0xFF) {
			PORTD |= _BV(7);
		}
	}
}

Не работает...

KivApple ★★★★★
() автор топика

Я кстати так и не допетрил как отличать на аврке два нуля от одного. Туго с совпадениями частот ресивера и пепедатчика. А хотелось пульт присобачить...

minakov ★★★★★
()
Ответ на: комментарий от KivApple

Должна быть - ИК приёмник видит передачу. А там демодулятор частоты стоит.

Не, это я чтобы убедиться. Это я понимаю. Если бы частота ушла, то сигнал бы на TSOP пропадал. В TSOP стоит узкополосный фильтр. Короче, модуляция есть вроде.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

А какой AVR?

Короче, дружище. У тебя на самом деле одна послыка 0xff выглядит так:

      +--+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  
      |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  
 -----+  +--+  +--+  +--+  +--+  +--+  +--+  +--+  +-------
MCUCR &= ~_BV(ISC01);
MCUCR |= _BV(ISC00);

А это: Any logical change on INT0 generates an interrupt request. У тебя как раз 16 раз меняется уровень с «1» на «0» и с «0» на «1». Ставь на rising edge - будет 8 прерываний.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

А, невнимательно прочел. Это так тебе и надо, чтобы было 16 прерываний. Значит, проблема только у тебя в том, что PD2 читается всегда 1. А это точно так? Ты как узнал?

Zubok ★★★★★
()
Ответ на: комментарий от KivApple

Однако, каждый раз с PIND почему-то читается единица (что значит, что сигнала нет). С другой стороны, если бы состояние вывода не становилось иногда нулевым, не было бы изменения уровня и INT0 не случился бы. Так что проблема в программе.

Как у тебя PORTD, DDRD сконфигурированы?

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Как у тебя PORTD, DDRD сконфигурированы?

Надо сконфигурировать PB2 как вход, то есть

DDRD &= ~_BV(2);
PORTD &= ~_BV(2);

Pull-up можно делать, а можно и не делать.

Zubok ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.