FIRST VERSION OF CODE: USING I2C NATIVE REGISTERS LIBRARY DATASHEET 18F26K22 NO WORK CODE LOCKED IN FMfrequenc() IN PARTICUTAL IN My_i2c_Read() implementation function. SSP1STAT.BF Wait for ever singnal to read data from buffer
I want traslate one FM-Receiver AR1010 library wrote for pic 16x
for my 18F26k22 pic.
subsequently I rewrote the library in a faithful way to the original in according whit 18F26k22 datascheet comparing whit 16F7x datasheet.some progress has been made on the implemented i2c library. I was inspired by a certain source, the link is the following: https://deepbluembedded.com/i2c-communi ... orial-pic/
now the i2c implementation is better written, but there is still something wrong!
discution and files update to 14.Mar.2021 19.51 My_I2C_Read() changed for Master I2C
Code: Select all
///////////////////// I2C IMPLEMENTATION for 18F26k22/////////////////////////
// https://deepbluembedded.com/i2c-communication-protocol-tutorial-pic/
// I2C MASTER
//
// _asm bsf LATA,1;
// _asm bcf LATA,1;
///////////////////////////////////////////////////////////////////
// OpenI2C( MASTER, SLEW_OFF);
#define _XTAL_FREQ 64000000 // Fosc In this case i have set internal oscillator
// Int Osc 16Mhx x 4 PLL = 64Mhz
#define I2C_BaudRate 400000 // I2C Baud Rate = 100 Kbps
void OpenI2C(unsigned char, unsigned char);
void My_I2C_Master_Init(void);
void My_I2C_Idle(void); //void I2C_Wait(void);
void My_I2C_Start(void);
void My_I2C_Stop(void);
void My_I2C_Restart(void);
void My_I2C_ACK(void);
void My_I2C_NACK(void);
unsigned char My_I2C_Write(unsigned char Data);
unsigned char My_I2C_Read(void);
void My_I2C_Master_Init(void)
{
SSP1CON1 = 0x28; //Select and enable master mode WCOL SSPOV SSPEN CKP SSPM<3:0>
SSP1CON2 = 0x00; //GCEN ACKSTAT ACKDT ACKEN RCEN PEN RSEN SEN
SSP1STAT = 0x00; //SMP CKE D/A P S R/W UA BF
SSP1ADD = ((_XTAL_FREQ/4)/I2C_BaudRate) - 1;
TRISC.B3 = 1; // scl pin.
TRISC.B4 = 1; // SDA pin.
SSP1CON1.SSPEN = 1; // added after
}
void My_I2C_Idle()
{
while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));
}
void My_I2C_Start()
{
//---[ Initiate I2C Start Condition Sequence ]---
My_I2C_Idle();
SSP1CON2.SEN = 1;
}
void My_I2C_Stop()
{
//---[ Initiate I2C Stop Condition Sequence ]---
My_I2C_Idle();
SSP1CON2.PEN = 1;
}
void My_I2C_Restart()
{
//---[ Initiate I2C Restart Condition Sequence ]---
My_I2C_Idle();
SSP1CON2.RSEN = 1;
}
void My_I2C_ACK(void)
{
//---[ Send ACK - For Master Receiver Mode ]---
My_I2C_Idle();
SSP1CON2.ACKDT = 0; // 0 -> ACK, 1 -> NACK
SSP1CON2.ACKEN = 1; // Send ACK Signal!
}
void My_I2C_NACK(void)
{
//---[ Send NACK - For Master Receiver Mode ]---
My_I2C_Idle();
SSP1CON2.ACKDT = 1; // 1 -> NACK, 0 -> ACK
SSP1CON2.ACKEN = 1; // Send NACK Signal!
}
unsigned char My_I2C_Write(unsigned char Data)
{
//---[ Send Byte, Return The ACK/NACK ]---
My_I2C_Idle();
SSPBUF = Data;
My_I2C_Idle();
return SSP1CON2.ACKSTAT;
}
unsigned char My_I2C_Read(void){
if((SSP1CON1 & 0x0F) == 0x08) SSP1CON2.RCEN = 1; // MASTER MODE ONLY
while(!SSP1STAT.BF); // WAIT UNTIL BYTE RECEIVED
return SSP1BUF; // RETURN WHIT READ BYTE
}
Code: Select all
/*
File: fm.h
Project: LDPS IV FM Radio project
Created: Spring 2014
Created by: Lab group 8 - Josh Tyler, Vilma Wilke, Umair Hassan and Le Huy Hoang (based on skeletal code provided by RAC)
Purpose: Provide constants and function definitions used by main.c
Language: C (Complied with the XC8 compiler on MPLABX)
Target: PIC16F84A
*/
#define XS 0 // Exit success
#define XF 1 // Exit fail
#define FMI2CADR 0x20 // Address (for writes) of FM module on I2C bus
#define DEVRD 0x01 // Read not write an I2C device
#define FMCHIPVERSADR 0x1C //0x06 //0x1C // Address of FM chip version
#define FMCHIPIDADR 0x1B // Address of FM chip ID
#define FMCHIPSTSADR 0x13 // Address of FM chip status
#define READCHAN_ADR 0x13
#define FMASKMUTE 0x0001 // Register 1, bit 1
#define FMASKTUNE 0x0200 // Register 2, bit 9
#define FMASKSTATUS 0x0020 // Register 0x13, bit 5
#define FMASKSEEK 0x4000 // Register 3, bit 14
#define FMASKRDCHAN 0xFF80 // Register 2, channel number bits
#define BUTN1 0b00000001 // Button number one
#define BUTN2 0b00000010 // Button number two
#define BUTN3 0b00000100
#define BUTN4 0b00001000
#define BUTN5 0b00010000
#define BUTN6 0b00100000
#define BUTN7 0b01000000
#define BUTN8 0b10000000
#define LCDSEGDP3 22 // LCD segment for decimal point
#define LCDSEGZ 23 // LCD segment for Z
#define FREQMAX 1080 // Maximum frequency
#define FREQMIN 875 // Minimum frequency
#define FMHIGHCHAN (1080-690) // Highest FM channel number
#define FMLOWCHAN (875-690)
#define FALSE 0
#define TRUE 1
// this part is not used because i not use display 7 segments
/*
#define LCD_3A 0 // LCDDATA0
#define LCD_3B 1
#define LCD_3C 2
#define LCD_3D 3
#define LCD_3E 4
#define LCD_3F 5
#define LCD_3G 6
#define LCD_DP1 7
#define LCD_2A 8 // LCDDATA1
#define LCD_2B 9
#define LCD_2C 10
#define LCD_2D 11
#define LCD_2E 12
#define LCD_2F 13
#define LCD_2G 14
#define LCD_DP2 15
#define LCD_1A 16 // LCDDATA2
#define LCD_1B 17
#define LCD_1C 18
#define LCD_1D 19
#define LCD_1E 20
#define LCD_1F 21
#define LCD_1G 22
#define LCD_DP3 23
#define LCD_K 24
#define LCD_COL 25
#define LCD_Z 26
*/
#define CHAR_DISP_DELAY 60 // Delay used for displaying text
/* Masks used to clear volume bits */
#define VOL1_MASK 0xF87F
#define VOL2_MASK 0x0FFF
/* Masks used to clear scan bits*/
#define SCAN_REG3_MASK 0x1FFF
#define SCAN_REG10_MASK 0xFFF7
/* Recommended values for volume, obtained from data sheet, repackaged for actual location in memory */
const int volumePair[2][19] = {
{0x0780, 0x0780, 0x0780, 0x0780, 0x0580, 0x0580, 0x0580, 0x0500, 0x0480, 0x0400, 0x0380, 0x0300, 0x0300, 0x0300, 0x0180, 0x0180, 0x0100, 0x0080, 0x0000} , /* Values for R3 */
{0x0000, 0xC000, 0xD000, 0xF000, 0xC000, 0xD000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xD000, 0xE000, 0xF000, 0xE000, 0xF000, 0xF000, 0xF000, 0xF000} /* Values for R14 */
};
const unsigned int station[6] = {875, 881, 903, 964, 1046, 1129};
char stationName[6][15] = { "UNKNOWN", "BBC[TWO", "BBC[THREE", "EAGLE", "BBC[ONE", "UNKNOWN" };
enum { // Global error numbers
GERNONE, // No error
GERWCOL, // I2C write collision
GERFINT, // Could not initialize FM module
GERFMID // Could not read chip ID (0x1010)
};
void Init(); // Processor initialisation.
void dly(int d);
unsigned char butnEvent(unsigned char *butn);
unsigned char testPinState(unsigned char oldPin, unsigned char newPin, unsigned char *butn);
void setscn(unsigned char state);
void segWrt(unsigned char segOrd, unsigned char state);
void charWrt(unsigned char numToDisp, unsigned char DigitNo);
unsigned int manualTune(unsigned int freq, unsigned char dir);
unsigned char FMread(unsigned char regAddr , unsigned int *data_);
unsigned char FMwrite(unsigned char adr); // Write a new value to a register
unsigned char FMinit(); // Initialise the chip
unsigned char FMfrequenc(unsigned int f);
unsigned char FMready(unsigned int *rdy); // Status is ready or busy
unsigned char FMid(unsigned int *id); // Obtain ID number
unsigned char showFreq(unsigned int frequency); // Display the current f in MHz
unsigned char FMvers(unsigned int *vsn); // Obtain version number
unsigned int volSet(unsigned int vol, unsigned char dir);
unsigned int nextChan(unsigned int chan, unsigned char dir);
void errfm(void);
unsigned char showVol(unsigned int volume);
unsigned char showChan(unsigned int channel);
unsigned int setScan(unsigned char dir);
int displayText(char str[], int pos);
//
// end receiveFM.h ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
//
Code: Select all
/////////////////////////// AR1010 FR RECEIVER TEST ///////////////////////
// 18F26K22 INTERNAL CLOCK 16MHZ X 4 PLL = 64MHZ
// ORIGINAL PROGECT LINK : https://github.com/joshtyler/PIC-FM
//
// PIN OUT:
// Encoder_SW3 --> RA4 (pin6) NEED TO CONNECT
// Encoder_DT3 --> RA3 (pin5) NEED TO CONNECT
// Encoder_CLK3 --> RA2 (pin4) NEED TO CONNECT
// AR 1010 FR RECEIVER ON I2C BUS
// SSD 1306 OLED DISPLAY ON I2C BUS
//
// NOTES:
// _asm bsf LATA,1;
// _asm bcf LATA,1;
//
///////////////////////////////////////////////////////////////////////////
// SSD1306 OLED reset pin definition (if available)
#define SSD1306_RST RC5_bit //RD4_bit
#define SSD1306_RST_DIR TRISC5_bit //TRISD4_bit
// SERVICE COSTANT DEFINITIONS
#define MAX_LEN1 128
#define MIN_LEN1 50
#define CR 0x0D
#define CLS 12
// LINK TO EXTERNAL LIBRARY
#include <stdbool.h>
#include <SSD1306OLED.c>
#include "fm.h"
#include "i2c18f26k22.c"
char txt[11];
unsigned char count10us,count100us,count10ms,count1sec;
unsigned char loop_time_sync;
//////////////////// PIN CONNECTIONS ///////////////////
sbit Encoder_SW3 at RA4_bit;
sbit Encoder_DT3 at RA3_bit; //(pin5)
sbit Encoder_CLK3 at RA2_bit; //(pin4)
sbit Encoder_SW3_Direction at TRISA4_bit;
sbit Encoder_DT3_Direction at TRISA3_bit;
sbit Encoder_CLK3_Direction at TRISA2_bit;
//////////////////////////////////////////////////////////
// FM register bank default values -
const unsigned int regDflt[18] = {
0xFFFF, // R0 -- the first writable register . (disable xo_en)
0x5B15, // R1.
0xD0B9, // R2.
0xA010, // R3 seekTHD = 16
0x0780, // R4
0x28AB, // R5
0x6400, // R6
0x1EE7, // R7
0x7141, // R8
0x007D, // R9
0x82C6, // R10 disable wrap
0x4F55, // R11. <--- (disable xo_output)
0x970C, // R12.
0xB845, // R13
0xFC2D, // R14
0x8097, // R15
0x04A1, // R16
0xDF6A // R17
};
unsigned int regImg[18]; // FM register bank images
////////////////////////////////////////////////////
/////////////// INTERRUPT SECTION ////////////////
////////////////////////////////////////////////////
void interrupt() iv 0x0008 ics ICS_AUTO /* Receive ISR routine void interrupt ISR()*/
{
if (TMR0IF_bit){
//INTERRUPT EVERY 10US
TMR0IF_bit = 0;
TMR0L = 0x60;
//Enter your code here
count10us++;
//if(count10us >=5) count50usBit=1;
if(count10us >=10){ //if reached 100us
count10us=0;
count100us++;
if(count100us>=100) { //if reached 10ms
count100us=0;
loop_time_sync++;
count10ms++;
if(count10ms>=100){ //if reached 1sec
count10ms=0;
if(count1sec<60) {
count1sec++; //_asm btg LATA,1;
} // btg = toggle bit redled1
else count1sec=0;
}
}
} //END if(count10us.....
} // END TIMER 1 INTERRUPT
} // END GLOBAL INTERRUPT
void InitTimer0(){
T0CON = 0xC8;
TMR0L = 0x60;
GIE_bit = 1;
TMR0IE_bit = 1;
}
////////////////////////////////////////////////////
/////////// END INTERRUPT SECTION //////////////
////////////////////////////////////////////////////
/*
* manualTune() - Manually tunes the channel
*
* @param dir Sets which way the frequency is changed, zero for up,
* nonzero for down.
*
* @param freq holds the frequency value.
*
* @return frequency on success or XF on error.
*
*/
unsigned int manualTune(unsigned int freq, unsigned char dir) {
switch (dir)
{
case TRUE : //manual up
if(freq < FREQMAX) //checks that frequency is valid
{
freq++;
FMfrequenc(freq); //sends incremented new value to FM chip
} else {
freq = FREQMIN;
FMfrequenc(freq);
}
break;
case FALSE : //manual down
if(freq > FREQMIN)
{
freq--;
FMfrequenc(freq);
} else {
freq = FREQMAX;
FMfrequenc(freq);
}
break;
default :
errfm(); // Call error subroutine
break;
}
return freq;
}
/*
* FMwrite() - Write a two byte word to the FM module. The new
* register contents are obtained from the image bank.
*
* @param adr The address of the register in the FM module that needs
* to be written.
*
*
* @return XS on success or XF on error.
*
*/
unsigned char FMwrite(unsigned char adr) {
char value[4];
unsigned int regstr;
unsigned char firstByt;
unsigned char secndByt;
unsigned char rpy;
firstByt = regImg[adr] >> 8;
secndByt = regImg[adr];
my_i2c_Start(); // Begin I2C communication
my_i2c_Idle();
// Send slave address of the chip onto the bus
if (My_I2C_Write(FMI2CADR)) return XF;
//UART1_Write_Text(" Function FmWrite Fbyte/Sbyte/Adr:");
//byteToStr(firstByt,value);UART1_Write_Text(value);UART1_Write_Text(" ");
//intToStr(secndByt,value);UART1_Write_Text(value);UART1_Write_Text(" ");
//intToStr(adr,value);UART1_Write_Text(value);UART1_Write_Text("\r\n");
My_I2C_Idle();
My_I2C_Write(adr); // Adress the internal register
My_I2C_Idle();
My_I2C_Write(firstByt); // Ask for write to FM chip
My_I2C_Idle();
My_I2C_Write(secndByt);
My_I2C_Idle();
My_I2C_Stop();
My_I2C_Idle();
return XS;
}
/*
* FMread - Read a two byte register from the FM module.
*
* @param regAddr The address of the register in the module that needs
* to be read.
*
* @param data Where to store the reading.
*
* @return XS on success or XF on error.
*
*/
unsigned char FMread(unsigned char regAddr, unsigned int *data_) {
char value[8];
unsigned char firstByt;
unsigned char secndByt;
My_I2C_Start(); // Begin I2C communication
My_I2C_Idle(); // Allow the bus to settle
// Send address of the chip onto the bus
if (My_I2C_Write(FMI2CADR)) return XF; // return 0
My_I2C_Idle();
My_I2C_Write(regAddr); // Adress the internal register
My_I2C_Idle();
My_I2C_Restart(); // Initiate a RESTART command
My_I2C_Idle();
My_I2C_Write(FMI2CADR + DEVRD); // Ask for read from FM chip
My_I2C_Idle();
firstByt = My_I2C_Read(); // Returns the MSB byte
My_I2C_Idle();
My_I2C_ACK; // Send back Acknowledge
My_I2C_Idle();
secndByt = My_I2C_Read(); // Returns the LSB of the temperature
My_I2C_Idle();
My_I2C_NACK();
My_I2C_Idle();
My_I2C_Stop();
My_I2C_Idle();
*data_ = firstByt;
*data_ <<= 8;
*data_ = *data_ | secndByt;
//UART1_Write_Text(" Function FmRead *data_:");
//intToStr(*data_,value);UART1_Write_Text(value);UART1_Write_Text("\r\n");
return XS;
}
/*
* FMready - See if the FM module is ready.
*
* @param rdy Where to store the busy/ready status. Will become
* non-zero if the chip is ready, zero if busy.
*
*
*
* @return XS on success or XF on error.
*
*/
unsigned char FMready(unsigned int *rdy) {
unsigned int sts;
if (FMread(FMCHIPSTSADR, &sts) != XS) return XF;
//_asm bsf LATA,1;
sts &= FMASKSTATUS;
*rdy = sts ? TRUE : FALSE;
return XS;
}
/*
* FMinit() - Initialise the FM module.
*
*
* @return XS on success or XF on error.
*
*/
unsigned char FMinit() {
unsigned char ad;
unsigned int dat;
// Copy default FM register values to the image set -
for(ad = 0; ad < 18; ad++) regImg[ad] = regDflt[ad];
dat = regImg[0];
regImg[0] &= ~1;
if (FMwrite(0) != XS) return XF;
// lo passa
for(ad = 1; ad < 18; ad++) {
if (FMwrite(ad) != XS)return XF;
}
regImg[0] = dat | 1;
if (FMwrite(0) != XS) return XF;
// lo passa
Delay_ms(20);//dly(20);
while (FMready(&dat), !dat) Delay_ms(2); //dly(2);
// lo passa
return XS;
}
/*
* FMfrequenc(f) - Tune the FM module to new frequency.
*
*
* @param f The new frequency as a multiple of 100 kHz.
*
* @return XS on success or XF on error.
*
*/
unsigned char FMfrequenc(unsigned int f) {
char value[8];
unsigned int dat;
unsigned int cn; // AR1010 channel number
cn = f - 690;
// NB AR1010 retunes on 0 to 1 transition of TUNE bit -
regImg[2] &= ~FMASKTUNE;
if (FMwrite(2) != XS)
return XF;
regImg[2] &= 0xfe00;
regImg[2] |= (cn | FMASKTUNE);
if (FMwrite(2) != XS)
return XF;
do {
Delay_ms(2); //dly(2);
if (FMready(&dat) != XS) // return 0
return XF;
_asm btg LATA,1;
//UART1_Write_Text("FMfrequenc() dat:");intToStr(dat,value);UART1_Write_Text(value);
} while (!dat);
return XF; // Code will never get to here.
}
/*
* FMvers - Obtain the FM chip version.
*
* @param vsn Where to store the version number. Will become
* 0x65B1 for vintage 2009 devices.
*
* @return XS on success or XF on error. *
*/
unsigned char FMvers(unsigned int *vsn) { // vsn=55
char temp;
char value[4];
temp=FMread(FMCHIPVERSADR, vsn);
UART1_Write_Text("FMread:");shortToStr(temp,value);UART1_Write_Text(value);
if (temp != XS) return XF;
return XS;
}
/*
* FMid - Obtain the FM chip ID.
* * @param id Where to store the ID number. Will become
* 0x1010 for AR1010 devices.
*
* @return XS on success or XF on error. *
*/
unsigned char FMid(unsigned int *id) {
if (FMread(FMCHIPIDADR, id) != XS) return XF;
return XS;
}
/*
* volSet() - Changes the volume
*
* @param dir Sets which way the volume is changed, TRUE for up,
* FALSE for down.
*
* @param vol holds the volume value.
*
* @return volume on success. On failure, enter error loop.
*
*/
unsigned int volSet(unsigned int vol, unsigned char dir) {
switch (dir)
{
case TRUE : //volume up
if(vol < 18) //checks that new volume is valid
{
vol++;
/* Clear the volume bits but leave other bits intact */
regImg[3] &= VOL1_MASK;
regImg[14] &= VOL2_MASK;
/* OR the mask with the current regImg value */
regImg[3] |= volumePair[0][vol];
regImg[14] |= volumePair[1][vol];
FMwrite(3); /*Calls function FMwrite to write new volume values to the FM chip*/
FMwrite(14);
}
break;
case FALSE :
if(vol > 0)
{
vol--;
/* Clear the volume bits but leave other bits intact */
regImg[3] &= VOL1_MASK;
regImg[14] &= VOL2_MASK;
regImg[3] |= volumePair[0][vol];
regImg[14] |= volumePair[1][vol];
FMwrite(3);
FMwrite(14);
}
break;
default :
errfm();
break;
}
return vol;
}
/*
* nextChan() - Tune to the next channel.
*
* @param up Set to TRUE for next channel up,
* FALSE for preset down.
*
* @return XS on success or XF on error.
*
*/
unsigned int nextChan(unsigned int chan, unsigned char dir) {
switch (dir)
{
case TRUE : //manual up
if(chan < 5) //checks that the selection is valid ***NOTE CHANGE****
{
chan++;
FMfrequenc(station[chan]); //sends stored value to FM chip
} else {
chan = 0;
FMfrequenc(station[chan]);
}
break;
case FALSE : //manual down
if(chan > 0)
{
chan--;
FMfrequenc(station[chan]);
} else {
chan = 5;
FMfrequenc(station[chan]);
}
break;
default :
//errfm();
break;
}
return chan;
}
void errfm(void) {
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(2, 7);
SSD1306_Print("FM Error");
SSD1306_Display();
}
/*
* setScan() - Scan up or down
*
* @param dir Sets which way to scan, zero for up,
* nonzero for down.
*
* Returns the new frequency
*/
unsigned int setScan(unsigned char dir) {
char value[8];
unsigned int dat;
unsigned int chanRgstr;
int reg3Wrd;
regImg[1] |= 0x0002; // Set hmute
FMwrite(1);
regImg[2] &=0xFDFF; //Clear Tune bit
FMwrite(2);
regImg[3] &=0xBFFF; // Clear Seek Bit
FMwrite(3);
regImg[3] |= 0x4000; // Set SEEK bit
regImg[3] |= 0x2000; // Set spacing
if(dir == 1)
regImg[3] |= 0x8000; // If dir is 1, set SEEKUP bit
else
regImg[3] &= 0x7FFF; // Otherwise clear to seek down
regImg[3] &= 0xE7FF; // Clear BAND
regImg[3] &= 0xFF80; // Mask all but seek threshold
regImg[3] |= 0x0040; // Set seek threshold
regImg[10] |= 0x0008; // Set wrap bit
FMwrite(10); // Write the bits to memory
FMwrite(3);
/* Now wait until finished scanning */
do {
Delay_ms(2); //dly(2);
if (FMready(&dat) != XS) return XF; //XS=0 XF=1
//UART1_Write_Text(" setScan() &dat:");
//intToStr(&dat,value);UART1_Write_Text(value);UART1_Write_Text("\r\n");
_asm btg LATA,1;
} while (!dat);
/* Read new channel */
if ( FMread(READCHAN_ADR, &chanRgstr) == XF)
errfm();
chanRgstr >>= 7;
chanRgstr &= 0x01FF; // Ensure that all bits apart from READCHAN are clear
regImg[2] &= 0xFE00; //Mask off CHAN
regImg[2] |= chanRgstr; // OR with current channel
FMwrite(2);
chanRgstr += 690;
regImg[1] &= 0xFFFD; // Clear hmute
FMwrite(1);
return chanRgstr;
}
void clear_screen(){ UART1_Write_Text("\033"); UART1_Write_Text("[2J"); }
void SSD_Display(unsigned int value) {
char text[8];
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
intToStr(value, text);
SSD1306_Print(text);
SSD1306_Display();
}
// main function
void main()
{
/////// IMPORTANT PROGRAM LOOPPED EVERY TIMR IN TO FMfrequenc
////// IN PARTICULAR IN DO{................}while(!DAT)
char value[8];
char value2[4];
short Temp;
short Sw3Sel,Sw3PrevSel;
bit position3;
unsigned char btn = 0b00000000; // Initialise btn to no buttons being pressed.
unsigned char evt;
unsigned int ui;
unsigned int freq = 875; //Stores frequency
unsigned int vol = 10; //Stores volume
unsigned int chan = 0; //Stores channel
unsigned int counter = 0;
unsigned int charDispCtr = CHAR_DISP_DELAY;
unsigned char toggle = false;
unsigned char disp = 'F'; // Stores display state
int dispOfst;
// internal FOSC 16MHz x 4PLL => 64MHz
OSCCON.IRCF2=1;
OSCCON.IRCF1=1;
OSCCON.IRCF0=1;
OSCTUNE.PLLEN=1;
OSCCON2.MFIOSEL = 0;
OSCTUNE.INTSRC = 1;
//TRISA=0b00000000;
//PORTA=0;
// Disable comparators
C1ON_bit = 0;
C2ON_bit = 0;
CM1CON0=0;
CM2CON0=0;
ANSELA = 0b00000001; // select ch0 for SpectrumAnalizer
ANSELB = 0x00; // configure all PORTB pins as digital
ANSELC = 0X00; // configure all PORTc pins as digital
TRISA = 0b00011101; // set A0 as input, A1....A7 as output
//rb2,rb3,rb4 as Multiplexer outputs
TRISB = 0b00000000; // set RB2,RB3,TB4 OUTPUT, Other RB5....RB77 as output
//TRISC = 0b00000111; // set C0,C1,C2 as input, C3....C7 as output
PORTA=0; PORTB=0; PORTC=1;
Encoder_SW3_Direction=1; Encoder_DT3_Direction=1; Encoder_CLK3_Direction=1;
///////////////////////////// INIT TIMER 0 ///////////////////////////
InitTimer0(); // NECESSARY IN THIS TEST
/////////////////////////////////////////////////////////////////////
Delay_ms(500); // wait a second
I2C1_Init(400000); // initialize I2C communication with clock frequency of 400kHz
// initialize the SSD1306 OLED with an I2C addr = 0x7A (default address)
// 128*64
SSD1306_Begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);
//SSD1306_ClearDisplay(); // clear the buffer
//SSP1CON1.SSPEN = 1;
My_I2C_Master_Init();
Delay_ms(200);
UART1_Init(9600);
//clear_screen();
UART1_Write(CLS); // Erase screen terminal :it is an option on Vbray Terminal!
UART1_Write_Text("Start debug: \r\n");
SSD1306_ClearDisplay();
for(dispOfst=0; dispOfst<6; dispOfst++)
{
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(2, 7);
SSD1306_Print("hello world!");
SSD1306_Display();
Delay_ms(100);
}
FMvers(&ui); // Check we have comms with FM chip
/*
// was this address
if (ui != 0x1010)
errfm();
*/
if (ui != 0x10FF) // new address 0x10FF 4351 (dec)
errfm();
UART1_Write_Text(" ui:"); IntToStr(ui,value);UART1_Write_Text(value);
temp=FMinit();
if (temp != XS) //XS=0
errfm();
UART1_Write_Text(" FmInt:");byteToStr(temp,value2);UART1_Write_Text(value2);
FMfrequenc(freq); // Initialise frequency
vol=volSet(vol,true); // Initialise volume to 10
freq = setScan(TRUE);
Sw3Sel=1;
while(1) {
// invert the display
//_asm btg LATA,1;
//SSD1306_InvertDisplay(true);
//Delay_ms(1000);
//LATA.B7=1; //redled1
//PORTA.B3=1;
//SSD1306_InvertDisplay(false);
//LATA.B7=1; //redled1
//PORTA.B3=0;
//Delay_ms(1000);
/*
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
intToStr(freq, value);
SSD1306_Print("out of case");
SSD1306_Display();
*/
/*
// Delay_ms(20); //dly(20); // delay to debounce switches
switch(disp)
{
case 'F':
//showFreq(freq);
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
intToStr(freq, value);
SSD1306_Print(value);
SSD1306_Display();
break;
case 'C':
//showChan(chan);
break;
case 'V':
//showVol(vol);
break;
case 'S':
if(charDispCtr == 0)
{
//dispOfst = displayText(stationName[chan],dispOfst);
charDispCtr = CHAR_DISP_DELAY;
if(dispOfst == 0)
disp = 'F';
}
else
charDispCtr--;
break;
default:
errfm();
break;
}
if (toggle == true) // Volume counter loop
{
counter = 100;
toggle = false;
}
else if(disp == 'V')
{
if (counter != 0)
counter--;
else
disp = 'F';
}
//evt = butnEvent(&btn);
if (evt == 1) switch (btn) {
case BUTN2 : //preset up
chan=nextChan(chan, true);
freq = station[chan];
disp = 'S';
//toggle = TRUE;
dispOfst = 0;
break;
case BUTN7 : // preset down
chan=nextChan(chan, false);
freq = station[chan];
disp = 'S';
//toggle = TRUE;
dispOfst = 0;
break;
case BUTN3 : //manual tuning up
freq=manualTune(freq, true);
disp = 'F';
break;
case BUTN6 : //manual tuning down
freq=manualTune(freq, false);
disp = 'F';
break;
case BUTN4 : // volume up
vol=volSet(vol, true);
disp = 'V';
toggle = TRUE;
break;
case BUTN5 : // volume down
vol=volSet(vol, false);
disp = 'V';
toggle = TRUE;
break;
case BUTN1 : // scan up
freq = setScan(true);
disp = 'F';
vol = volSet(vol, true); // Reset Volume
vol = volSet(vol, false);
break;
case BUTN8 : // Scan down
freq = setScan(false);
disp = 'F';
vol = volSet(vol, true); // Reset Volume
vol = volSet(vol, false);
break;
default:
break;
}
evt=0;
*/
////////// ROTARY-3 SELECTION //////////
if(Button(&PORTA,4,1000,0)) {
if(Sw3Sel<4) { _asm bsf LATA,1; Delay_ms(100);_asm bcf LATA,1;Sw3Sel++; }
else{
Sw3Sel=1; //SSD1306_ClearDisplay();
}
}
/*
UART1_Write_Text(" Sw3Sel:"); byteToStr(Sw3Sel,value);UART1_Write_Text(value);
UART1_Write_Text(" \r\n");
*/
if(Sw3PrevSel != Sw3Sel) {
switch (Sw3Sel){
case 1:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Channel");
SSD1306_Display();
break;
case 2:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Tune");
SSD1306_Display();
break;
case 3:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Volume");
SSD1306_Display();
break;
case 4:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Scan");
SSD1306_Display();
break;
default:
Sw3Sel=0;
break;
/*
case 5:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Volume Up");
SSD1306_Display();
break;
case 6:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Volume Down");
SSD1306_Display();
break;
case 7:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Scan Up");
SSD1306_Display();
break;
case 8:
SSD1306_ClearDisplay(); // clear the buffer
SSD1306_Color = 1;
SSD1306_TextSize(1);
SSD1306_GotoXY(15, 30);
SSD1306_Print("Scan Down");
SSD1306_Display();
break;
*/
} // end case selection
Sw3PrevSel=Sw3Sel;
} // END if(Sw3PrevSel != Sw3Sel)
if (Encoder_CLK3 != position3){
//count1sec=0; // escape from menu in if(count1sec>=5)
// Decrease Value
if (Encoder_DT3 != position3){
_asm bsf LATA,1; Delay_ms(100);_asm bcf LATA,1;
if(Sw3Sel==1) {
chan=nextChan(chan, false);
freq = station[chan];
SSD_Display(chan);
//freq=manualTune(freq, false);
}
if(Sw3Sel==2) {
freq=manualTune(freq, false);
SSD_Display(freq);
//freq=manualTune(freq, false);
}
if(Sw3Sel==3) {
vol=volSet(vol, false);
SSD_Display(vol);
}
if(Sw3Sel==4) {
freq = setScan(false);
SSD_Display(freq);
vol = volSet(vol, true); // Reset Volume
vol = volSet(vol, false);
}
}
// Increase Value
else{
_asm bsf LATA,1; Delay_ms(100);_asm bcf LATA,1;
if(Sw3Sel==1) {
chan=nextChan(chan, true);
freq = station[chan];
SSD_Display(chan);
//freq=manualTune(freq, true);
}
if(Sw3Sel==2) {
freq=manualTune(freq, true);
SSD_Display(freq);
//freq=manualTune(freq, true);
}
if(Sw3Sel==3) {
vol=volSet(vol, true);
SSD_Display(vol);
}
if(Sw3Sel==4) {
freq = setScan(true);
SSD_Display(freq);
vol = volSet(vol, true); // Reset Volume
vol = volSet(vol, false);
}
}
} // End if (Encoder_CLK3 != position)
position3 = Encoder_CLK3;
////////// END ROTARY-2 INPUT SELECTION //////////
} // end while(1);
}
// end of code.
If you want try the entire project you could find it in attachement togheder documentation I2c Protocol explained very well: