📄 serial.c
字号:
/****************************************************************
*
* Microchip 16-bit Embedded Control Design Contest
*
* Entry # MT2268
*
* Spa Pump Controller
*
*****************************************************************
*
* Serial communication routines
*
*****************************************************************/
#include "PumpCtl.h"
#include "Serial.h"
#include "Periph.h"
#include "ADC.h"
#include "Inverter.h"
#include "PFC.h"
#define SW_VERSION 0x01 // Software version
#define DEV_ADDR 0 // Device address (0 or 1)
#define BAUD 9600 // Serial baud rate
#define PING_TIMEOUT 750 // Keep-alive timeout (1 - 64K msec)
#define COMM_TIMEOUT 100 // Command receive timeout (1 - 255 msec)
enum { // Command codes
CMD_echo = 1,
CMD_get_ver = 2,
CMD_get_stat = 3,
CMD_set_mode = 4,
CMD_get_speed = 5,
CMD_set_speed = 6,
CMD_set_ramp = 7,
CMD_set_parm_lo = 16,
CMD_get_parm_lo = 32,
CMD_set_parm_hi = 16 + 64,
CMD_get_parm_hi = 32 + 64
};
static BYTE comm_buf[3]; // Command buffer
static BYTE comm_count; // Byte count
#define MAX_N_PARMS 16 // Maximum size of each parm table
#define N_RO_PARMS (sizeof (ro_parm_tbl) / sizeof (WORD *)) // Actual table size
#define N_RW_PARMS (sizeof (rw_parm_tbl) / sizeof (WORD *))
WORD *const ro_parm_tbl[] = { // Read-only parameters
&sys_fault,
&sys_state,
&inv_state,
&pfc_state,
&meas.nv.vsns_ac,
(WORD *)&meas.nv.vsns_ac_pk + 1, // high word only
&meas.nv.vsns_bus,
&meas.nv.isns_pfc,
&meas.nv.isns_aux,
&meas.nv.isns_run,
&meas.nv.isns_com,
&meas.nv.temp_pfc,
&meas.nv.temp_inv,
};
WORD *const rw_parm_tbl[] = { // Read-write parameters
&sys_mode.w,
&pfcp.v_gain_p,
&pfcp.v_gain_f,
&pfcp.i_gain_p,
&pfcp.i_gain_i,
&pfcp.i_gain_lim,
&pfcp.v_nom,
&pfcp.v_low_thr,
&pfcp.v_high_thr,
&pfcp.max_duty,
(WORD *)&invp.ramp,
&invp.ampl_var,
&invp.delta_nom,
&invp.delta_thr,
&invp.offset_nom,
&invp.offset_thr,
};
BYTE Exec_cmd (BYTE cmd, BYTE data);
/*
Serial comm task handler, called by the main routine
Receive a command block from the serial port,
execute the command, and send back a response.
*/
void Comm_run (void)
{
WORD i;
BYTE result;
// Wait until the transmit FIFO is empty, so we can write out
// the entire response block at once without additional buffering.
if (Serial_Xempty () == 0) {
i = Serial_Recv (); // Check for incoming data
if (i != SERIAL_EOF) { // Byte received
comm_buf[comm_count] = i; // Save it in buffer
comm_count ++; // Incr buffer count
comm_timer = 0; // Clear comm timeout
if (comm_count == 3) { // Entire command received
if (((comm_buf[0]+comm_buf[1]+comm_buf[2]) & 0xFF) == 0xFF // Checksum OK
&& (comm_buf[0] & 0x80) == (DEV_ADDR << 7)) { // Our address
result = Exec_cmd (comm_buf[0], comm_buf[1]); // Do the command
i = Serial_Xmit (comm_buf[0]); // Transmit result block
if (i == 0) {
i = Serial_Xmit (result);
if (i == 0)
i = Serial_Xmit (0xFF - ((comm_buf[0] + result) & 0xFF));
}
if (i == 0)
ping_timer = 0;
else
sys_fault |= FAULT_ser_xmit;
}
comm_count = 0; // Clear buffer byte count
}
}
}
if (comm_count != 0) // If partial command received
if (comm_timer >= COMM_TIMEOUT) // but we've waited too long,
comm_count = 0; // clear command buffer
if (ping_timer >= PING_TIMEOUT) // If nothing received for too long,
sys_fault |= FAULT_ping_time; // set fault flag
}
/*
Execute a command
*/
BYTE Exec_cmd (BYTE cmd, BYTE data)
{
BYTE result;
if (cmd >= CMD_get_parm_lo + MAX_N_PARMS // Get a read-only parm (0x30-3F)
&& cmd < CMD_get_parm_lo + MAX_N_PARMS + N_RO_PARMS)
return ((*ro_parm_tbl[cmd - (CMD_get_parm_lo + MAX_N_PARMS)]) & 0xFF);
if (cmd >= CMD_get_parm_hi + MAX_N_PARMS // Get high byte (0x70-7F)
&& cmd < CMD_get_parm_hi + MAX_N_PARMS + N_RO_PARMS)
return ((*ro_parm_tbl[cmd - (CMD_get_parm_hi + MAX_N_PARMS)]) >> 8);
if (cmd >= CMD_get_parm_lo // Get a read/write parm (0x20-2F)
&& cmd < CMD_get_parm_lo + N_RW_PARMS)
return ((*rw_parm_tbl[cmd - CMD_get_parm_lo]) & 0xFF);
if (cmd >= CMD_get_parm_hi // Get high byte (0x60-6F)
&& cmd < CMD_get_parm_hi + N_RW_PARMS)
return ((*rw_parm_tbl[cmd - CMD_get_parm_hi]) >> 8);
if (cmd >= CMD_set_parm_lo // Set a read/write parm (0x10-1F)
&& cmd < CMD_set_parm_lo + N_RW_PARMS) {
*(BYTE *) (*rw_parm_tbl[cmd - CMD_set_parm_lo]) = data;
return (0);
}
if (cmd >= CMD_set_parm_hi // Set high byte (0x50-5F)
&& cmd < CMD_set_parm_hi + N_RW_PARMS) {
*(BYTE *) ((*rw_parm_tbl[cmd - CMD_set_parm_hi]) + 1) = data;
return (0);
}
switch (cmd) {
case CMD_echo: // Echo received data
return (data);
break;
case CMD_get_ver: // Get software version
return (SW_VERSION);
break;
case CMD_get_stat: // Get running and fault status
result = 0;
if (inv_state == RUNNING || inv_state == RAMP_UP || inv_state == RAMP_DOWN)
result |= 0x80;
if (pfc_state == P_RUNNING)
result |= 0x40;
if (sys_fault & 0x8000)
result |= 0x04;
if (sys_fault & 0x7F00)
result |= 0x02;
if (sys_fault & 0x00FF)
result |= 0x01;
return (result);
break;
case CMD_set_mode: // Set running mode & clear faults
if (data & 0x80)
Inv_start ();
else
Inv_stop ();
if (data & 0x01)
sys_fault = 0;
return (0);
break;
case CMD_get_speed: // Get inverter frequency
return (Inv_get_freq ());
break;
case CMD_set_speed: // Set inverter frequency
if (data != 0)
Inv_set_freq (data);
else
Inv_stop ();
return (0);
break;
case CMD_set_ramp: // Not yet supported!
return (0);
break;
default:
return (0xFF);
break;
}
}
/*
Initialize serial port
*/
void Serial_init (void)
{
U1BRG = ((((LONG) FRC_CLK_FREQ * 2000UL) + (BAUD * 16UL / 2UL)) / (BAUD * 16UL)) - 1;
U1MODEbits.UARTEN = 1;
U1STAbits.UTXEN = 1;
}
/*
Receive a character, or return SERIAL_EOF if none
*/
WORD Serial_Recv (void)
{
BYTE data;
if (! U1STAbits.URXDA)
return (SERIAL_EOF);
data = U1RXREG;
return (data);
}
/*
Transmit a character, or return SERIAL_ERR if not ready
*/
WORD Serial_Xmit (BYTE data)
{
if (U1STAbits.UTXBF)
return (SERIAL_ERR);
U1TXREG = data;
return (0);
}
/*
Check if serial FIFO is empty, return SERIAL_ERR if not
*/
WORD Serial_Xempty (void)
{
if (! U1STAbits.TRMT) // Transmit FIFO not empty
return (SERIAL_ERR);
return (0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -