📄 ssp.c
字号:
// ssp.c
// Tom Perme
// Microchip Technology Inc.
// 2007
#include "main887.h"
#include "ssp.h"
void SSPInit(void);
void SSPISR(void);
void LoadSSPBUF(void);
void UnloadSSPBUF(void);
/*....................................................................
. SSPInit()
.
. Initializes pins and registers for SSP use.
....................................................................*/
void SSPInit(void) {
int i;
// SSP Pins
TRISSDA = 1; // SDA = 1nput (digital i/p, ANSEL set by Cap. init)
TRISSCL = 1; // SCL = 1nput (digital i/p, ANSEL set by Cap. init)
// Initialize Module
SSPCON = 0x00; // Clear Reg, then set appropriate bits.
SSPEN = 1; // Enable module
CKP = 1; // Enable Clock
SSPM3 = 1; // Set for I2C slave, 7-bit addr, S & P intpts
SSPM2 = 1; // "
SSPM1 = 1; // "
SSPM0 = 0;
GCEN = 0; // Clear general call enable interrupt (only react to device address)
SSPADD = DEVICE_ADDR; // Set device address to respond to, mask bits default 0xFF to match all.
SMP = 1; // Set for sample rate ~100kHz
SSPIF = 0; // Clear flag in case prexists as set PIR1
SSPIE = 1; // Enable SSP Interrupt
PEIE = 1; // Enable Peripheral Interrupts
/* GIE Needs to be set when ready to enable all interrupts. */
// Init Ram Variables
Flags.SSPBF = 0;
ByteCount = 0;
}
/*....................................................................
. High level call that determines what action to take. Call
. this function whenever an SSPIF flag is detected whether under
. read or write conditions. The condition will be sorted out,
. and the appropriate action will be taken to make the device
. act as EEPROM.
....................................................................*/
void SSPISR(void) {
SSPIF = CLEAR; // Clear interrupt flag right away
// 1. Check if I have a start or stop condition
// 2. Service Starts and Stops differently
// 3. Service byte transmissions read/write as appropriate
if (STOP == 1) {
// Stop Condition
Flags.SSPBF = CLEAR;
// Wrap-up Transmission
SSPOV = CLEAR; // Clear overflow err if applicable
CKP = SET; // Enable clock again
return; // Return to end SSP use
} else if (RW == 0 && BF == 0) {
// Start Condition
Flags.SSPBF = SET; // Set SSP Busy Flag
SSPOV = CLEAR; // Clear overflow err if applicable
CKP = SET; // Enable clock again
return; // Return to finish start interrupt
}
// If not a Start or Stop, perform the read or write of a byte
if (DA == 0) { // DEVICE ADDRESS BYTE, determine if R/W
if (RW == 0) { // Write byte
ByteCount = SSPBUF; // Read SSPBUF to clear BF flag (destination not critical)
ByteCount = 0; // Clear ByteCount for start of Write(s)
} else { // Read Byte
// { Master expecting data to be sent from address at SSPBUF }
CKP = 0; // Ensure clock disabled
LoadSSPBUF(); // Load SSPBUF and prep for next pass
}
} else { // DATA BYTE
if (RW == 0) { // Write Byte
if (ByteCount == 0) { // 2nd Byte received by slave, (command byte)
SSPCommand = SSPBUF; // Index for where to read is byte received over SSP.
ByteCount++; // Increment BC for next pass to keep track of byte meanings
} else if (ByteCount == 1) { // 3rd Write Byte received by slave, (index byte)
SSPIndex = SSPBUF; // Get the index of sensor to start readings
ByteCount++; // Keep track of received bytes from Master
} else if (ByteCount == 2) { // 4th Write Byte received by slave, (size byte)
SSPSize = SSPBUF; // How many sensors to operate upon
if (SSPCommand != WRITE_SENSOR) // For all but read funcs, reset bc
ByteCount = 0; // Clear ByteCount to start over - for use with reads, helps 0-base index values
else
ByteCount++;
} else { // Receiving data byte
// { Note no bounds checking }
UnloadSSPBUF(); // Take Contents of SSPBUF and place into data arrays
}
} else { // Read Byte
// { Send data to master. }
CKP = CLEAR; // disable clock line
LoadSSPBUF(); // Load SSPBUF and prep for next pass
}
}
// Finished servicing byte
SSPOV = CLEAR; // Clear overflow err if applicable
CKP = SET; // Enable clock again
return;
}
/*....................................................................
. LoadSSPBUF()
.
. Loads the SSPBUF register with the appropriate data. Since
. the data is stored as 2-byte integers, and only 1 byte may be sent
. over the SSP at a time, the byte must be loaded in the correct
. byte of each integer variable.
. (Reads bytes from PIC to Master)
....................................................................*/
void LoadSSPBUF(void) {
if (SSPCommand == READ_RAW_AVG) {
// Command byte says to reply to the Master with Raw and Avg data for requested sensors
// RAW
if (ByteCount < 2*SSPSize) {
// Send raw data for requested sensors
// First entrance, setup index counter
if (ByteCount == 0)
IndexCount = SSPIndex;
// Send the data
SSPBUF = (ByteCount % 2) ? RAW[IndexCount] : RAW[IndexCount] >> 8; // Load SSPBUF with raw data
// AVG
} else {
// For read raw/avg, there is only avg left
// First entrance, set up index counter
if (ByteCount == 2*SSPSize*1)
IndexCount = SSPIndex;
// Send the data
SSPBUF = (ByteCount % 2) ? AVERAGE[IndexCount] : AVERAGE[IndexCount] >> 8; // Load SSPBUF with raw data
}
} else if (SSPCommand == READ_ALL) {
// Reply to the Master with RAW, AVERAGE, TRIP, and GUARd
if (ByteCount < 2*SSPSize) {
// RAW
// ...
// First entrance, setup index counter
if (ByteCount == 0)
IndexCount = SSPIndex;
// Send the data
SSPBUF = (ByteCount % 2) ? RAW[IndexCount] : RAW[IndexCount] >> 8; // Load SSPBUF with raw data
} else if (ByteCount <2*SSPSize*2) {
// AVERAGE
// ...
// First entrance, set up index counter
if (ByteCount == 2*SSPSize*1) // Detects rolling from above if, into this else if
IndexCount = SSPIndex;
// Send the data
SSPBUF = (ByteCount % 2) ? AVERAGE[IndexCount] : AVERAGE[IndexCount] >> 8; // Load SSPBUF with data
} else if (ByteCount <2*SSPSize*3) { // 2*SSPSize*3 enters trip byte region
// TRIP
// ...
// First entrance, set up index counter
if (ByteCount == 2*SSPSize*2)
IndexCount = SSPIndex;
// Send the data
SSPBUF = (ByteCount % 2) ? TRIP[IndexCount] : TRIP[IndexCount] >> 8; // Load SSPBUF with data
} else if (ByteCount <2*SSPSize*4) {
// GUARD
// ...
// First entrance, set up index counter
if (ByteCount == 2*SSPSize*3)
IndexCount = SSPIndex;
// Send the data
SSPBUF = (ByteCount % 2) ? GUARD[IndexCount] : GUARD[IndexCount] >> 8; // Load SSPBUF with data
}
} else if (SSPCommand == READ_NUM_SENSORS) {
// This one is easy..
SSPBUF = NUM_BTTNS; // Report the number of buttons in the system
}
// After each read..
// Increment byte counter, index counter handled based on func
ByteCount++; // Byte counter is for actual byte of dat
// with new bytecount value, choose to incr. integer index or not
if (ByteCount % 2 == 0)
IndexCount++; // Increment IndexCounter on byte basis (may be reset to start index by func in if's above)
}
/*....................................................................
. UnloadSSPBUF()
.
. Unloads the SSPBUF register into the appropriate data. Since
. the data is stored as 2-byte integers, and only 1 byte may be sent
. over the SSP at a time, this makes the PIC act like EEPROM.
. (Writes bytes from Master into PIC)
....................................................................*/
void UnloadSSPBUF(void) {
TempInt = SSPBUF; // Load incoming byte into variable
// Store Data to Array
// ...
if (SSPCommand == WRITE_SENSOR) {
// Write data to the sensor specified
// TrpU TrpL GbU GbL
// ByteCount 3 4 5 6
// (future note: to make extensible, subtract offset of 3 off of BC, or reset to 0-based index another way)
// (for this simple interface, it was simplest to do it as below)
// High Bytes
if (ByteCount == 3) // Trip high byte
TRIP[SSPIndex] = TempInt << 8; // Mul Incoming Byte by 256, shift 8, to get into high byte
else if (ByteCount == 5) // Guard high byte
GUARD[SSPIndex] = TempInt << 8; // Shift up to high byte
// Low Bytes
if (ByteCount == 4) {
TRIP[SSPIndex] &= 0xFF00; // Clear Low byte
TRIP[SSPIndex] |= TempInt; // Store SSPBUF (Low byte) to raw data
} else if (ByteCount == 6) {
GUARD[SSPIndex] &= 0xFF00; // Clear Low byte
GUARD[SSPIndex] |= TempInt; // Store SSPBUF (Low byte) to raw data
}
}
ByteCount++; // Increment byte recvd counter
}
/*....................................................................
. SetMasterMode()
.
. Configures SSP for I2C master mode. This function should be
. used prior to communicating from the 16F887 circuit to the 16F677
. over the SDA and SCL lines.
....................................................................*/
void SetMasterMode(void) {
// Set SSPM of SSPCON to 1000 for master mode
SSPEN = 0;
SSPCON |= 0b00001000; // SSPM = 1xxx
SSPCON &= 0b11111000; // SSPM = x000 --> SSPM = 1000
SSPEN = 1;
}
/*....................................................................
. SetSlaveMode()
.
. Configures SSP for I2C slave mode. This function should be
. used prior to communicating from the 16F887 circuit to the user's
. computer through the PICkit Serial Analyzer.
....................................................................*/
void SetSlaveMode(void) {
// Set for I2C slave, 7-bit addr, S & P intpts, SSPM = 1110
SSPEN = 0;
SSPCON |= 0b00001110; // SSPM = 111x
SSPCON &= 0b11111110; // SSPM = xxx0 --> SSPM = 1110
SSPEN = 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -