📄 main.c
字号:
/*
Copyright (C) 2006 Marc Ketel
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define INFO "20060629-1 RDS Decoder by Marc Ketel alias DiNo, marc@atoomnet.net."
/*
Works with RDS clock signal and RDS data signal. During design a TDA7300B rds demodulator was used.
This source compiles correctly with WinAVR 20060421.
Use a Atmega168 to flash program into. low fuse: 0xF0, high fuse: 0xDD
Versions:
20060629-1 Initial version
*/
/*
general word on ISR: it does not seem that ISR has global interrupts disabled.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <stdio.h>
#include <math.h>
#define RDS_PORT PIND
#define RDS_PIN PD4
FILE* Uart;
//used for stdout
int uartSend(char data, FILE* stream) {
//wait for completion of previous send
loop_until_bit_is_set(UCSR0A, UDRE0);
//send the data
UDR0 = data;
return 0;
}
//used for stdin
int uartRecv(FILE* stream) {
loop_until_bit_is_set(UCSR0A, RXC0);
return UDR0;
}
volatile unsigned char event = 0;
#define eventTimerOverflow _BV(0)
#define eventUsart0RxDInterrupt _BV(1)
#define eventGroupComplete _BV(2)
#define eventBitstreamSnapshot _BV(3)
#define eventSyncLost _BV(4)
volatile unsigned char timerOverflowCount = 0;
volatile unsigned char usart0RxDByte = 0;
volatile unsigned char bitCounter = 0;
volatile unsigned char bitCounterSnapshot = 0;
volatile unsigned char synchronized = 0;
volatile unsigned char syncQuality = 0; //0-31, 0=no useable signal, 15=medium quality, 31=perfect!
volatile unsigned char syncCounter = 0;
volatile unsigned char block = 0;
volatile unsigned long bitstream = 0;
volatile unsigned long bitstreamData = 0;
volatile unsigned int block1 = 0;
volatile unsigned int block2 = 0;
volatile unsigned int block3 = 0;
volatile unsigned int block4 = 0;
//ISR is executed when there is a new rds bit to read
ISR(INT0_vect) {
cli();
unsigned int syndrome = 0;
//Copy global vars to local vars for performance
unsigned long bitstreamLocal = bitstream;
unsigned char blockLocal = block;
//shift rds bit in on right side
bitstreamLocal *= 2;
if (RDS_PORT & _BV(RDS_PIN))
bitstreamLocal++;
bitCounter++;
//collect data for raw bitstream snapshots
bitCounterSnapshot++;
if (bitCounterSnapshot == 26) {
bitstreamData = (bitstreamLocal & 0x3FFFFFF);
bitCounterSnapshot = 0;
event |= eventBitstreamSnapshot;
}
//when we have 26 bits or are not synchronized to the stream
//check the CRC and maybe store a rds block
if (bitCounter == 26 || !synchronized) {
bitstreamLocal &= 0x3FFFFFF; //we only need 26 bits
syndrome = (bitstreamLocal / 0x10000); //bits 16-31 (2^16)
if (bitstreamLocal & _BV(0))
syndrome ^= 0x031b;
if (bitstreamLocal & _BV(1))
syndrome ^= 0x038f;
if (bitstreamLocal & _BV(2))
syndrome ^= 0x02a7;
if (bitstreamLocal & _BV(3))
syndrome ^= 0x00f7;
if (bitstreamLocal & _BV(4))
syndrome ^= 0x01ee;
if (bitstreamLocal & _BV(5))
syndrome ^= 0x03dc;
if (bitstreamLocal & _BV(6))
syndrome ^= 0x0201;
if (bitstreamLocal & _BV(7))
syndrome ^= 0x01bb;
if (bitstreamLocal & _BV(8))
syndrome ^= 0x0376;
if (bitstreamLocal & _BV(9))
syndrome ^= 0x0355;
if (bitstreamLocal & _BV(10))
syndrome ^= 0x0313;
if (bitstreamLocal & _BV(11))
syndrome ^= 0x039f;
if (bitstreamLocal & _BV(12))
syndrome ^= 0x0287;
if (bitstreamLocal & _BV(13))
syndrome ^= 0x00b7;
if (bitstreamLocal & _BV(14))
syndrome ^= 0x016e;
if (bitstreamLocal & 0b1000000000000000) // _BV(15) does not work!!!
syndrome ^= 0x02dc;
//Block A?
if (blockLocal == 0 && syndrome == 0x03d8) {
block1 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
synchronized = 1;
blockLocal++;
} else
//Block B?
if (blockLocal == 1 && syndrome == 0x03d4) {
block2 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
synchronized = 1;
blockLocal++;
} else
//Block C type A?
if (blockLocal == 2 && !(block2 & _BV(11)) && syndrome == 0x025c) {
block3 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
synchronized = 1;
blockLocal++;
} else
//Block C type B?
if (blockLocal == 2 && (block2 & _BV(11)) && syndrome == 0x03cc) {
block3 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
synchronized = 1;
blockLocal++;
} else
//Block D?
if (blockLocal == 3 && syndrome == 0x0258) {
block4 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
synchronized = 1;
blockLocal = 0;
//we have a complete group!
event |= eventGroupComplete;
} else {
//sync lost..
synchronized = 0;
blockLocal = 0;
event |= eventSyncLost;
}
bitCounter = 0;
}
if (event & eventGroupComplete) {
PORTC |= _BV(PC1);
if (syncQuality < 31)
syncQuality++;
} else if (!synchronized) {
PORTC &= ~_BV(PC1);
syncCounter++;
if (syncQuality > 0 && syncCounter == 26) {
syncQuality--;
syncCounter = 0;
}
}
if (syncQuality >= 15)
PORTC |= _BV(PC2);
else
PORTC &= ~_BV(PC2);
//Store local vars into global vars to remember state
bitstream = bitstreamLocal;
block = blockLocal;
sei();
}
//timer0 overflowed
ISR(TIMER0_OVF_vect) {
cli();
timerOverflowCount++;
if (timerOverflowCount > 4) {
event |= eventTimerOverflow;
timerOverflowCount = 0;
}
sei();
}
ISR(USART_RX_vect) {
cli();
usart0RxDByte = UDR0;
event |= eventUsart0RxDInterrupt;
sei();
}
void displayInfo(void) {
printf_P(PSTR("INFO: 0x01, "));
printf_P(PSTR(INFO));
printf_P(PSTR("\r\n"));
}
int main(void) {
wdt_reset(); //reset inmediately in case of a previous system reset
//lets enable watchdog with 1 second timeout
wdt_enable(WDTO_1S);
unsigned int programmeIdentificationCode = 0;
unsigned char groupType = 0;
unsigned char groupVersion = 0;
unsigned char trafficProgrammeIdentificationCode = 0;
unsigned char programmeTypeCode = 0;
unsigned char trafficAnnouncementCode = 0;
unsigned char musicSpeechSwitchScode = 0;
unsigned char group0CodeBits = 0;
unsigned char group0CodeBitsSteadyCount = 0;
unsigned char programmeServiceName[8];
unsigned char programmeServiceNameNew[8];
unsigned char decoderIdentificationControlCode = 0;
unsigned char decoderIdentificationControlCodeNew = 0;
unsigned char alternativeFrequencyCodes[27];
unsigned char syncMessage = 0;
unsigned char displayRaw = 0;
unsigned char displayBitstream = 0;
unsigned char linkageActuator = 0;
unsigned char extendedCountryCode = 0;
unsigned char textSegmentAddress = 0;
unsigned char textSegmentAddressPrevious = 0;
unsigned char textVersion = 0;
unsigned char textVersionPrevious = 0;
unsigned char radioText[64];
unsigned char radioTextPrevious[64];
unsigned char textSegmentAddress0Seen = 0;
unsigned int modifiedJulianDay = 0;
unsigned int utcYear = 0;
unsigned char utcMonth = 0;
unsigned char utcDay = 0;
signed char localHours = 0;
unsigned char utcHours = 0;
signed char localMinutes = 0;
unsigned char utcMinutes = 0;
unsigned char utcMinutesPrevious = 0xFF;
unsigned char localSign = 0;
unsigned int localTimeOffset = 0;
//general purpose vars
unsigned int m;
unsigned char h;
unsigned char i;
unsigned char j;
//1.8mhz crystal
//baudrate 115.2K
//UBRR0 = 0;
//baudrate 9600
//UBRR0 = 11;
//16mhz crystal
//38.4k
//UBRR0 = 25;
//4.332Mhz crystal
//baudrate 38K4
UBRR0 = 6;
//enable RxD interrupt, RxD, TxD
UCSR0B |= _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
//8 bit
//UCSR0C |= _BV(UCSZ00) | _BV(UCSZ01);
//UART is stdout and stdin;
Uart = fdevopen(uartSend, uartRecv);
//enable int0
EIMSK = _BV(INT0);
//INT0 raising edge
EICRA |= _BV(ISC01) | _BV(ISC00);
//PC0, PC1, PC2 are outputs;
DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC2);
//timer0 prescaler clk/1024
TCCR0B |= _BV(CS02) | _BV(CS00);
//enable overflow interrupt
TIMSK0 |= _BV(TOIE0);
displayInfo();
sei(); //enable interrupts;
for (;;) {
do {} while (!event);
wdt_reset(); //reset watchdog, we are still alive!
cli();
if (event & eventUsart0RxDInterrupt) {
event &= ~eventUsart0RxDInterrupt;
sei();
//collect the command
//switch group display on (G) or off (g)
if (usart0RxDByte == 'G')
displayRaw = 0;
else if (usart0RxDByte == 'g')
displayRaw = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -