[go: up one dir, main page]

0% found this document useful (0 votes)
20 views16 pages

Pinout

This document provides Arduino code to control the RDA1846 radio chip using I2C communication with an LCD display and a rotary encoder for frequency adjustment. It includes setup instructions, wiring diagrams, and function prototypes for initializing the RDA1846, setting its frequency, and updating the LCD display. The code is designed for Arduino Uno/Nano boards and requires specific libraries for functionality.

Uploaded by

mohsin siddique
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views16 pages

Pinout

This document provides Arduino code to control the RDA1846 radio chip using I2C communication with an LCD display and a rotary encoder for frequency adjustment. It includes setup instructions, wiring diagrams, and function prototypes for initializing the RDA1846, setting its frequency, and updating the LCD display. The code is designed for Arduino Uno/Nano boards and requires specific libraries for functionality.

Uploaded by

mohsin siddique
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

Okay, let's create the Arduino code to control the RDA1846.

This code will:

Use the Wire library for I2C communication with both the RDA1846 and the LCD.

Use the LiquidCrystal_I2C library for the LCD.

Use a common RotaryEncoder library (like the one by Matthias Hertel - you might need to install this via
the Arduino Library Manager) to handle the rotary encoder input.

Implement functions to initialize the RDA1846 and set its frequency based on the programming guide.

Display the current frequency on the LCD.

Allow frequency adjustment using the rotary encoder.

Set the RDA1846 to RX mode for the specified frequency (146.500 MHz initially, then adjustable).

Assumptions:

You are using an Arduino Uno/Nano or similar board.

The RDA1846's SEN pin is tied LOW, setting its I2C address to 0x71. If tied HIGH, change
RDA1846_I2C_ADDR to 0x2E.
You are using a 26 MHz crystal for the RDA1846 (as seen in the provided schematic example). If using
12.8 MHz or another, adjust the rda_init() values.

The LCD's I2C address is 0x27. Find yours using an I2C scanner sketch if needed.

Rotary Encoder Pins: CLK to D2, DT to D3, SW (Switch) to D4 (optional). D2 and D3 are required for
interrupts.

Libraries Needed:

Wire.h (Built-in)

LiquidCrystal_I2C.h (Install via Library Manager: Search for "LiquidCrystal I2C")

RotaryEncoder.h (Install via Library Manager: Search for "RotaryEncoder" by Matthias Hertel)

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

#include <RotaryEncoder.h>

// --- Configuration ---

// RDA1846 I2C Address (SEN=LOW -> 0x71, SEN=HIGH -> 0x2E)

#define RDA1846_I2C_ADDR 0x71

// LCD I2C Address (Commonly 0x27 or 0x3F) - Use I2C Scanner if unsure

#define LCD_I2C_ADDR 0x27


#define LCD_COLS 16

#define LCD_ROWS 2

// Rotary Encoder Pins (Must use interrupt pins for CLK/DT)

#define ROTARY_PIN_CLK 2 // Interrupt Pin 0 on Uno/Nano

#define ROTARY_PIN_DT 3 // Interrupt Pin 1 on Uno/Nano

// #define ROTARY_PIN_SW 4 // Optional Switch Pin

// Frequency Settings

#define INITIAL_FREQUENCY_HZ 146500000UL // 146.500 MHz

#define MIN_FREQUENCY_HZ 134000000UL // 134.000 MHz (VHF Band Limit)

#define MAX_FREQUENCY_HZ 174000000UL // 174.000 MHz (VHF Band Limit)

#define FREQUENCY_STEP_HZ 12500UL // 12.5 kHz step (common channel spacing)

// RDA1846 Crystal Frequency (Adjust if different)

#define XTAL_FREQ_HZ 26000000UL // 26 MHz

// RDA1846 Registers (Partial List)

#define REG_CHIP_ID 0x00 // Read only? Not explicitly listed for write

#define REG_SOFT_RESET 0x00 // Bit 0 = 1 to reset

#define REG_CLK_MODE 0x04

#define REG_PA_BIAS 0x0A

#define REG_RF_BAND 0x0F

#define REG_FREQ_HI 0x29

#define REG_FREQ_LO 0x2A


#define REG_XTAL_FREQ 0x2B

#define REG_ADC_CLK 0x2C

#define REG_CTRL 0x30 // TXON, RXON, Channel Mode, SQON, VOXON, PDN_REG, etc.

#define REG_VOLUME 0x44

#define REG_SUBAUDIO1 0x45 // Mode, Select, Detect Enable, etc.

#define REG_SQ_OPEN_TH 0x48

#define REG_SQ_SHUT_TH 0x49

#define REG_CTCSS_FREQ 0x4A

#define REG_CDCSS_HI 0x4B

#define REG_CDCSS_LO 0x4C

// --- Global Variables ---

LiquidCrystal_I2C lcd(LCD_I2C_ADDR, LCD_COLS, LCD_ROWS);

RotaryEncoder encoder(ROTARY_PIN_CLK, ROTARY_PIN_DT, RotaryEncoder::LatchMode::FOUR3); //


Use FOUR3 for better stability

volatile unsigned long currentFrequencyHz = INITIAL_FREQUENCY_HZ;

volatile bool frequencyChanged = true; // Start true to force initial set/update

long lastEncoderPos = 0;

// --- Function Prototypes ---

void rda_write_reg(byte regAddr, uint16_t data);

bool rda_init();

bool rda_set_frequency(unsigned long freqHz);

void update_lcd();

void handleEncoder(); // ISR function


// --- Setup ---

void setup() {

Serial.begin(115200);

Serial.println("RDA1846 Controller Starting...");

Wire.begin();

// Initialize LCD

lcd.init();

lcd.backlight();

lcd.clear();

lcd.setCursor(0, 0);

lcd.print("RDA1846 Control");

// Attach Encoder Interrupts

attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_CLK), handleEncoder, CHANGE);

attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_DT), handleEncoder, CHANGE);

// Initialize RDA1846

if (!rda_init()) {

Serial.println("RDA1846 Init Failed!");

lcd.setCursor(0, 1);

lcd.print("RDA Init FAIL");

while (1); // Halt on failure


}

Serial.println("RDA1846 Initialized.");

// Set Initial Frequency explicitly

rda_set_frequency(currentFrequencyHz);

frequencyChanged = true; // Ensure LCD updates

delay(1000); // Wait a bit

lcd.clear();

// --- Main Loop ---

void loop() {

// Encoder reading is handled by interrupts now.

// We just check the flag set by the ISR.

if (frequencyChanged) {

noInterrupts(); // Disable interrupts temporarily

unsigned long freqToSet = currentFrequencyHz;

frequencyChanged = false; // Clear the flag

interrupts(); // Re-enable interrupts

Serial.print("Frequency Changed to: ");

Serial.print(freqToSet / 1000000.0, 3); // Print MHz with 3 decimals

Serial.println(" MHz");
if (rda_set_frequency(freqToSet)) {

update_lcd(); // Update display only if frequency set successfully

} else {

Serial.println("Failed to set frequency!");

// Optional: Display error on LCD

// Optional: Read encoder switch if connected

// if (digitalRead(ROTARY_PIN_SW) == LOW) {

// Serial.println("Encoder button pressed");

// // Add action for button press (e.g., toggle TX, scan, menu)

// delay(200); // Simple debounce

// }

delay(50); // Small delay to prevent busy-waiting

// --- Interrupt Service Routine for Encoder ---

void handleEncoder() {

encoder.tick(); // Process encoder state machine

long newPos = encoder.getPosition();


if (newPos != lastEncoderPos) {

if (newPos > lastEncoderPos) { // Clockwise

if (currentFrequencyHz <= MAX_FREQUENCY_HZ - FREQUENCY_STEP_HZ) {

currentFrequencyHz += FREQUENCY_STEP_HZ;

frequencyChanged = true;

} else {

currentFrequencyHz = MAX_FREQUENCY_HZ; // Clamp to max

frequencyChanged = true; // Still mark as changed if clamped

} else { // Counter-Clockwise

if (currentFrequencyHz >= MIN_FREQUENCY_HZ + FREQUENCY_STEP_HZ) {

currentFrequencyHz -= FREQUENCY_STEP_HZ;

frequencyChanged = true;

} else {

currentFrequencyHz = MIN_FREQUENCY_HZ; // Clamp to min

frequencyChanged = true; // Still mark as changed if clamped

lastEncoderPos = newPos;

// --- RDA1846 Functions ---


// Write 16-bit data to an RDA1846 register via I2C

void rda_write_reg(byte regAddr, uint16_t data) {

Wire.beginTransmission(RDA1846_I2C_ADDR);

Wire.write(regAddr); // Send register address

Wire.write((byte)(data >> 8)); // Send high byte of data

Wire.write((byte)(data & 0xFF)); // Send low byte of data

byte error = Wire.endTransmission();

if (error != 0) {

Serial.print("I2C Write Error Addr=0x");

Serial.print(regAddr, HEX);

Serial.print(", Error Code: ");

Serial.println(error);

// delayMicroseconds(50); // Small delay might be needed between writes for some I2C devices

// Initialize the RDA1846

bool rda_init() {

Serial.println("Initializing RDA1846...");

// Based on 26MHz Crystal and Programming Guide Defaults/Recommendations

// Refer to RDA1846 Programming Guide Rev 1.2 (or latest)

// 1. Configure Reference Clock (Section B.3)

// Assuming 26MHz crystal (adjust if different)


// clk_mode = 0 for 24-28MHz

// xtal_freq = (26/2)*1000 = 13000 (0x32C8)

// adclk_freq = (26/4)*1000 = 6500 (0x1964)

rda_write_reg(REG_CLK_MODE, 0x0F10); // Reg 04h: Default 0x0F11, set bit 0 to 0

rda_write_reg(REG_XTAL_FREQ, 0x32C8); // Reg 2Bh: 13000

rda_write_reg(REG_ADC_CLK, 0x1964); // Reg 2Ch: 6500

Serial.println("-> Clock Configured");

delay(10); // Allow clock to stabilize

// 2. Set RF Band (Section B.2)

// Band 11 = 134-174MHz needed for 146.500

// Default 0Fh is 0x0024. Need bits 7:6 = 11. Data = 0xE4.

rda_write_reg(REG_RF_BAND, 0x00E4); // Reg 0Fh

Serial.println("-> RF Band Set (VHF)");

// 3. Disable Subaudio/Squelch for basic RX test

rda_write_reg(REG_SUBAUDIO1, 0x0000); // Reg 45h: c_mode=0, disable related features

// Reg 30h default has SQ_ON (bit 3) = 0, so squelch should be off

// 4. Set Volume (Section B.14) - Optional, set mid-range

// Default is 0xFFFF. Let's try 0x0888 (roughly -7dB for both channels)

rda_write_reg(REG_VOLUME, 0x0888); // Reg 44h

Serial.println("-> Volume Set");

// 5. Set Channel Mode and Enable RX (Section B.4)


// Channel mode: 00 = 12.5kHz (bits 13:12)

// rx_on = 1 (bit 5)

// tx_on = 0 (bit 6)

// pdn_reg = 1 (bit 2 - must be high with PDN pin for normal operation)

// sq_on = 0 (bit 3)

// vox_on = 0 (bit 4)

// Other bits = 0 (st_mode, tail_elim)

// Value = 0000 0000 0010 0100 = 0x0024

// Wait, PDN_REG should be 1. So bit 2 is 1. Value = 0x0024

// Let's enable RX_ON (bit 5). Value = 0x0024

// Let's be explicit: rx_on=1 (bit 5), pdn_reg=1 (bit 2). Others 0 for now.

// 0000 0000 0010 0100 = 0x0024

rda_write_reg(REG_CTRL, 0x0024); // Reg 30h: Enable RX, PDN_REG=1, 12.5kHz Ch BW

Serial.println("-> RX Enabled, 12.5kHz BW");

// Note: Frequency is set separately after init

// Basic check - maybe read Chip ID if possible (needs read function)

// For now, assume success if no I2C errors printed

return true; // Assuming initialization is successful

// Set the RDA1846 operating frequency

bool rda_set_frequency(unsigned long freqHz) {

if (freqHz < MIN_FREQUENCY_HZ || freqHz > MAX_FREQUENCY_HZ) {


Serial.println("Error: Frequency out of VHF band limits!");

return false;

// Calculate the 30-bit frequency setting value (Section B.1)

// Freq<29:0> = Freq(MHz) * 1000 * 8

// Freq<29:0> = (freqHz / 1_000_000.0) * 1000 * 8

// Freq<29:0> = freqHz * 0.008

uint32_t freq_reg_val = (uint32_t)((double)freqHz * 0.008 + 0.5); // Add 0.5 for rounding

// Split into high (14 bits for 29H) and low (16 bits for 2AH) parts

uint16_t low_data = freq_reg_val & 0xFFFF; // freq<15:0>

uint16_t high_data = (freq_reg_val >> 16) & 0x3FFF; // freq<29:16> (Mask to 14 bits)

Serial.print("Setting Freq: "); Serial.print(freqHz); Serial.print(" Hz -> ");

Serial.print("RegVal=0x"); Serial.print(freq_reg_val, HEX);

Serial.print(" Hi=0x"); Serial.print(high_data, HEX);

Serial.print(" Lo=0x"); Serial.println(low_data, HEX);

// Write the frequency registers

rda_write_reg(REG_FREQ_HI, high_data); // Write high part first

rda_write_reg(REG_FREQ_LO, low_data); // Write low part

// Optional: Verify write (would need a read function)

return true;
}

// --- LCD Update Function ---

void update_lcd() {

char freqStr[17]; // Buffer for formatted string (16 chars + null)

double freqMHz = (double)currentFrequencyHz / 1000000.0;

// Format frequency string like "146.500 MHz RX"

sprintf(freqStr, "%7.3f MHz RX", freqMHz); // 7 chars total, 3 after decimal

lcd.clear(); // Clear entire display

lcd.setCursor(0, 0);

lcd.print("Frequency:");

lcd.setCursor(0, 1);

lcd.print(freqStr);

Explanation & How to Use:

Install Libraries: Make sure you have LiquidCrystal_I2C and RotaryEncoder (by Matthias Hertel) installed
in your Arduino IDE.

Wiring:

Arduino <-> LCD: Connect SDA to A4, SCL to A5, VCC to 5V, GND to GND.
Arduino <-> Rotary Encoder: Connect CLK to D2, DT to D3, GND to GND, + to 5V (if needed, some
modules have pull-ups). Optionally connect SW to D4.

Arduino <-> RDA1846:

Connect SDA to A4.

Connect SCL to A5.

Connect RDA1846 VDD/AVDD pins to a stable 3.3V supply (or the output of its LDO if using >3.3V
source). Do not connect directly to Arduino 5V.

Connect RDA1846 GND to Arduino GND.

Tie the RDA1846 SEN pin LOW (to GND) to use I2C address 0x71.

Tie the RDA1846 PDN pin HIGH (to 3.3V) to enable the chip (the code also sets the internal pdn_reg).

Connect the 26MHz crystal and its load capacitors (CX1, CX2 in the schematic) to XTAL1 and XTAL2 pins.

Connect Antenna circuitry (including RX/TX switch, PA, filters) as per RDA1846 typical application
schematics. For RX testing, you need at least the RFIN pin connected via a switch/filter to the antenna.

Connect speaker/audio output circuitry to AFOUT.

Connect Mic input to MIC_IN (not needed for basic RX test).


Configuration: Double-check RDA1846_I2C_ADDR, LCD_I2C_ADDR, and XTAL_FREQ_HZ in the code.

Upload: Upload the sketch to your Arduino.

Run:

Open the Serial Monitor at 115200 baud to see initialization messages and frequency changes.

The LCD should show the initial frequency (146.500 MHz RX).

Turn the rotary encoder. The frequency on the LCD and Serial Monitor should change in 12.5 kHz steps.

The RDA1846 is now configured and listening on the displayed frequency.

Test Reception:

Set your Baofeng UV-5R (or other radio) to the exact frequency displayed on the LCD (e.g., 146.500
MHz).

Ensure the Baofeng is set to Narrowband (NFM or MN) mode to match the 12.5kHz channel width set in
the code.

Ensure any CTCSS/DCS tones are OFF on the transmitting radio.

Transmit from the Baofeng. You should hear the audio from the speaker connected to the RDA1846's
AFOUT pin (via an amplifier if needed).
This code provides the fundamental control structure. You would need to add functions for reading
registers, enabling TX, handling squelch/CTCSS, etc., for more advanced features.

You might also like