Created
December 10, 2023 00:46
-
-
Save ajarmst/387dccd42c67664a7398eb8d9a7b01f0 to your computer and use it in GitHub Desktop.
I2C Demo 2 - Advanced RTC, Accelerometer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///////////////////////////////////////////////////////////////////////////// | |
// HC12 Program: I2C Demo 2 - Advanced RTC, Accelerometer | |
// Processor: MC9S12XDP512 | |
// Bus Speed: 20 MHz (Requires Active PLL) | |
// Author: AJ Armstrong | |
// Details: Demonstration of the I2C Driver Libraries | |
// Date: Dec 2023 | |
// Revision History : | |
///////////////////////////////////////////////////////////////////////////// | |
#include <stdio.h> // For sprintf, etc | |
#include <ctype.h> // For character utilities | |
#include <string.h> // Various string utilities | |
#include <hidef.h> // Common defines and macros | |
#include "derivative.h" // Derivative-specific definitions | |
#include "pll.h" // Phase-locked loop clock control | |
#include "swled.h" // GPIO switches and LEDs | |
#include "segs.h" // 7-Segment Displays | |
#include "timer.h" // Enhanced capture timer | |
#include "portj.h" // Interrupt buttons | |
#include "pit.h" // Periodic Interrupt timer | |
#include "rti.h" // Realtime interrupts | |
#include "lcd.h" // LCD Display | |
#include "sci.h" // Serial communications interface (EIA/TIA-232) | |
#include "i2c.h" // Carlos Estay's I2C Driver Libraries | |
///////////////////////////////////////////////////////////////////////////// | |
// Local Prototypes | |
///////////////////////////////////////////////////////////////////////////// | |
//Several demonstration functions for various devices | |
void Demo_RTC(); | |
void UploadRTCDate(RTC_Read date); | |
void DownloadRTCDate(RTC_Read* pdate); | |
void DisplayRTCDate(RTC_Read date); | |
void Demo_TPS(); | |
void Display_TPS(); | |
void Demo_ACC(); | |
void Display_ACC(); | |
void Demo_CMP(); | |
void Display_CMP(); | |
///////////////////////////////////////////////////////////////////////////// | |
// Global Variables | |
///////////////////////////////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////////////////// | |
// Constants | |
///////////////////////////////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////////////////// | |
// Main Entry | |
///////////////////////////////////////////////////////////////////////////// | |
void main(void) | |
{ | |
// Variables | |
RTC_Read dateTime; // Type for getting RTC data (see i2c.h) | |
///////////////////////////////////////////////////////////////////////////// | |
// One-Time Initializations | |
///////////////////////////////////////////////////////////////////////////// | |
_DISABLE_COP(); // No watchdog | |
PLL_To20MHz(); // Configure the main clock to 20 MHz (implications for timers) | |
SWL_Init(); // Standard initialization for switches and LEDs | |
SEG_Init(); // Standard initializaton for 7-seg displays | |
RTI_Init(); // Initialize RTI timer | |
///////////////////////////////////////////////////////////////////////////// | |
// Main Program Loop | |
///////////////////////////////////////////////////////////////////////////// | |
EnableInterrupts; // Ensure our board will respond to interrupt signals. | |
LCD_Init(); // Current LCD drivers need RTI and interrupts. //FIXME | |
LCD_StringJustify(0,"I2C Demo",eLCD_Just_Center); | |
LCD_StringJustify(1,"========",eLCD_Just_Center); | |
// First, initialize the I2C at fast (400 kbps) speed | |
I2C0_InitBus(I2CBus400); | |
//Run Device Setups | |
Demo_RTC(); | |
Demo_ACC(); | |
//The big loop | |
for (;;) | |
{ | |
//Show current state of RTC | |
if(!(rtiCount % 10000)) // Every 10 seconds | |
{ | |
DownloadRTCDate(&dateTime); //Get current datetime from RTC | |
DisplayRTCDate(dateTime); //Display | |
} | |
//Show acceleration on axes | |
if(!(rtiCount % 1000)) // 1 per second | |
{ | |
Display_ACC(); | |
} | |
asm WAI; // Wait for something exciting to happen | |
} | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// Functions | |
///////////////////////////////////////////////////////////////////////////// | |
////////////////////////////////////////////////// | |
// RTC - Real Time Clock (0x68) | |
////////////////////////////////////////////////// | |
void Demo_RTC() // Function to demonstrate the RTC (based on previous demo) | |
{ | |
// This demo will use the M41T81S already built into our board and attached | |
// at address 0x68 (RTC_ADD in header) | |
RTC_Read dateTime; // Type for getting RTC data (see i2c.h) | |
int test = 0; // For capturing return values | |
char reg = 0; // For capturing single byte results | |
// Test for STOP flag by trying to read SECONDS | |
// register from the RTC. If the special bit | |
// 0x80 (STOP, RTC_SECONDS_ST) is set in the return, | |
// then is not running. | |
test = I2C0_RegRead(®, RTC_ADD, RTC_SECONDS); | |
if (reg & RTC_SECONDS_ST) // Stopped | |
{ | |
//Yellow LED means it was stopped. | |
SWL_SetLEDs(eYellow); | |
//Ok. Let's start it by rewriting a zero with | |
//the stop bit reset | |
reg = 0; //My current seconds are junk, so discarding | |
I2C0_RegWrite(RTC_ADD, RTC_SECONDS, reg & ~RTC_SECONDS_ST, IIC0_STOP); | |
} | |
//Also, if it was halted, that shows up in the AlarmHour register | |
//as the special bit 0x40 (RTC_AL_HOUR_HT) | |
//This is probably because the board was shut off or had a power | |
//failure. | |
test = I2C0_RegRead(®, RTC_ADD, RTC_AL_HOUR); | |
if (reg & RTC_AL_HOUR_HT) // Halted | |
{ | |
//Red LED means it was halted. | |
SWL_SetLEDs(eRed); | |
//Unhalt it by rewriting the value with the bit reset | |
I2C0_RegWrite(RTC_ADD, RTC_AL_HOUR, reg & ~RTC_AL_HOUR_HT, IIC0_STOP); | |
} | |
//Ok, that's what we had before. Now let's have a bit more fun. Let's create | |
//a struct with date/time just before midnight on New Year's eve: | |
dateTime.Year = 22; | |
dateTime.Month = Dec; | |
dateTime.MonthDay = 31; | |
dateTime.Day = Sat; | |
dateTime.Hours = 23; | |
dateTime.Minutes = 59; | |
dateTime.Seconds = 50; | |
dateTime.HuSeconds = 0; | |
//Throw that date up to the RTC | |
UploadRTCDate(dateTime); | |
//Remainder is in the main loop, displaying current RTC time, date. | |
} | |
//Send a date structure to the RTC | |
void UploadRTCDate(RTC_Read date) | |
{ | |
//Upload each field into the appropriate register in my RTC | |
//Note handling the bitfields because BCD | |
I2C0_RegWrite(RTC_ADD,RTC_HSECONDS,date.HuSeconds % 10 | ((date.HuSeconds /10 ) << 4),IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_SECONDS,date.Seconds % 10 | ((date.Seconds/10 ) << 4),IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_MINUTES,date.Minutes % 10 | ((date.Minutes/10 ) << 4),IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_CHOUR,date.Hours % 10 | ((date.Hours/10) << 4),IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_DAY,date.Day,IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_DATE,date.MonthDay % 10 | ((date.MonthDay/10 ) << 4),IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_MONTH,date.Month % 10 | ((date.Month/10 ) << 4),IIC0_STOP); | |
I2C0_RegWrite(RTC_ADD,RTC_YEAR,date.Year % 10 | ((date.Year/10 ) << 4),IIC0_STOP); | |
} | |
//Retrieve a date structure from the RTC | |
void DownloadRTCDate(RTC_Read* pdate) | |
{ | |
char reg = 0; | |
//Download each field, manipulate, then stuff into appropriate record in date pointed to by pdate. | |
I2C0_RegRead(®,RTC_ADD,RTC_HSECONDS); //Note handling the bitfields | |
// The arrow notation (pdate->HuSeconds) is shorthand for (*p).HuSeconds | |
pdate->HuSeconds = ((reg & 0xF0) >> 4) * 10 + (reg & 0x0F); // First nibble * 10 + second nibble | |
I2C0_RegRead(®,RTC_ADD,RTC_SECONDS); | |
pdate->Seconds = ((reg & 0xF0) >> 4) * 10 + (reg & 0x0F); | |
I2C0_RegRead(®,RTC_ADD,RTC_MINUTES); | |
pdate->Minutes = ((reg & 0xF0) >> 4) * 10 + (reg & 0x0F); | |
I2C0_RegRead(®,RTC_ADD,RTC_CHOUR); | |
pdate->Hours = ((reg & 0x30) >> 4) * 10 + (reg & 0x0F); //Note masking to only 2 bits | |
I2C0_RegRead(®,RTC_ADD,RTC_DAY); // No manipulation needed, load straight into struct | |
pdate->Day = reg; | |
I2C0_RegRead(®,RTC_ADD,RTC_DATE); | |
pdate->MonthDay = ((reg & 0x30) >> 4) * 10 + (reg & 0x0F); //Note masking to only 2 bits | |
I2C0_RegRead(®,RTC_ADD,RTC_MONTH); | |
pdate->Month = ((reg & 0xF0) >> 4) * 10 + (reg & 0x0F); | |
I2C0_RegRead(®,RTC_ADD,RTC_YEAR); | |
pdate->Year = ((reg & 0xF0) >> 4) * 10 + (reg & 0x0F); | |
} | |
void DisplayRTCDate(RTC_Read date) | |
{ | |
char szBuff[21] = {0}; //Buffer with enough room for one LCD line | |
char month[4]={0}; | |
char day[4]={0}; | |
switch(date.Day) | |
{ | |
case Sun: strcpy(day,"Sun"); break; | |
case Mon: strcpy(day,"Mon"); break; | |
case Tue: strcpy(day,"Tue"); break; | |
case Wed: strcpy(day,"Wed"); break; | |
case Thu: strcpy(day,"Thu"); break; | |
case Fri: strcpy(day,"Fri"); break; | |
case Sat: strcpy(day,"Sat"); break; | |
} | |
switch(date.Month) | |
{ | |
case Jan: strcpy(month,"Jan"); break; | |
case Feb: strcpy(month,"Feb"); break; | |
case Mar: strcpy(month,"Mar"); break; | |
case Apr: strcpy(month,"Apr"); break; | |
case May: strcpy(month,"May"); break; | |
case Jun: strcpy(month,"Jun"); break; | |
case Jul: strcpy(month,"Jul"); break; | |
case Aug: strcpy(month,"Aug"); break; | |
case Sep: strcpy(month,"Sep"); break; | |
case Oct: strcpy(month,"Oct"); break; | |
case Nov: strcpy(month,"Nov"); break; | |
case Dec: strcpy(month,"Dec"); break; | |
} | |
//Generate a Date string from the current date | |
sprintf(szBuff,"%s, %02d %s 20%02d", day, date.MonthDay, month, date.Year); | |
//Throw it to the LCD | |
LCD_StringJustify(2,szBuff,eLCD_Just_Center); | |
//Now put time on the upper segs. | |
SEG_8D(0,date.Hours); | |
SEG_8D(2,date.Minutes); | |
} | |
////////////////////////////////////////////////// | |
// ACC - Accelerometer (0x19) | |
////////////////////////////////////////////////// | |
void Demo_ACC() | |
{ | |
//Initialize the device | |
//0x19 - Device, 0x20 - CTRL_REG1_A, | |
//0x27 - 10 Hz, Normal power, all three axes | |
I2C0_RegWrite(0x19,0x20,0x27,IIC0_STOP); | |
//Settings | |
//0x23 - CTRL_REG4_A, 0x20 - Cont. Update, | |
// Big Endian, +/-2g, high res, 4 wire. | |
I2C0_RegWrite(0x19,0x23,0xC8,IIC0_STOP); | |
} | |
void Display_ACC() | |
{ | |
char status = 0; //Used for getting status of device | |
int x=0, y=0, z=0; //Holders for accel raw data | |
float gX = 0, gY = 0, gZ = 0; //Holders for acceleration in g's | |
int bHi=0, bLo=0; //Temp variables for high and low order nibbles | |
char szBuff[21] = {0}; //Buffer with enough room for one LCD line | |
//First, let's see if there is a value ready to be read | |
//0x27 is STATUS_REG_A -- accelerometer status | |
I2C0_RegRead(&status, 0x19, 0x27); | |
//Bit 3 is Data Available | |
if(!(status & 0b00001000)) // Zero in that bit means not avail | |
return; //Nothing to do. | |
//If I got here, I have data | |
SWL_SetLEDs(eYellow); //Yellow LED will signify an accelerometer update | |
//Get two bytes of accel, construct signed int (0x28,0x29 are X) | |
I2C0_RegRead(&bLo,0x19,0x28); | |
I2C0_RegRead(&bHi,0x19,0x29); | |
//Construct X (the shift is to take the left-aligned 12 of 16 bits to right-aligned) | |
//(the shift was determined experimentally, but I have not calibrated the device) | |
x = (((int)bHi << 8) + bLo) >> 4; //Milli-g's | |
gX = x/1000.0f; | |
//Get two bytes of accel, construct signed int (0x2A,0x2B are Y) | |
I2C0_RegRead(&bLo,0x19,0x2A); | |
I2C0_RegRead(&bHi,0x19,0x2B); | |
//Construct Y | |
y = (((int)bHi << 8) + bLo) >> 4; | |
gY = y/1000.0f; | |
//Get two bytes of accel, construct signed int (0x2C,0x2D are Z) | |
I2C0_RegRead(&bLo,0x19,0x2C); | |
I2C0_RegRead(&bHi,0x19,0x2D); | |
//Construct Z | |
z = (((int)bHi << 8) + bLo) >> 4; | |
gZ = z/1000.0f; | |
//Let's convert this into a nice string for the LCD | |
//(%+4.1f means minimum four characters, one digit after the dp, show sign) | |
sprintf(szBuff,"(%+4.1f,%+4.1f,%+4.1f)",gX,gY,gZ); | |
LCD_StringJustify(3,szBuff,eLCD_Just_Center); | |
SWL_ClearLEDs(eYellow); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment