This implementation of NETV, known as NETV8 (8 bits), is made to be used on any PIC18F micro controller with a serial connection to a PC. This guide describes how to use the library with your own project. This is the kind of implementation that is useful if you want to plot variables on a PC, tune a controller, run your hardware with scripts, etc. For an example project, refer to the [UControl] page.
[-img src=Netv ucontrol 1.png: missing =-]
[-img src=IMG 7163.JPG: missing =-]
First of all, you need to get the library from our SVN repository. Here are the files that you need:
Note: x is used for the architecture. For PIC18, x=8, for PIC24, dsPIC30 and dsPIC33F x=16, for PIC32 x=32.
Some files are application-specific for your project:
Note: this example is based on the [UControl] project.
In your main project file (let's call it main.c) you need to add includes:
#include "NETV8_SerialDriver.h"
#include "NETV8_Device.h"
#include "NETV8_Shared.h"
In void main (void) you need to add two lines at the top:
unsigned char canAddr = 0;
BootConfig *bootConfig = NULL;
and the boot config just before your while loop:
//reading boot config and device configuration
//MUST BE DONE BEFORE INITIALIZING NETV MODULE
bootConfig = netv_get_boot_config();
if (bootConfig)
{
//read configuration
netv_read_boot_config(bootConfig);
//safety
bootConfig->module_state = BOOT_NORMAL;
//verify if we have correct configuration
//write it back if not updated
if (bootConfig->table_version != MODULE_TABLE_VERSION
|| bootConfig->project_id != MODULE_PROJECT_ID
|| bootConfig->code_version != MODULE_CODE_VERSION)
{
bootConfig->table_version = MODULE_TABLE_VERSION;
bootConfig->project_id = MODULE_PROJECT_ID;
bootConfig->code_version = MODULE_CODE_VERSION;
//Set to default address
bootConfig->module_id = 1;
//Writing back the boot config for the next version
netv_write_boot_config(bootConfig);
//set variables to zero
init_default_variables();
}
}
//UPDATE NETV ADDRESS
canAddr = bootConfig->module_id;
In your main loop, you need to add the transceiver function. In that case, I also refresh my variables in the main loop.
//Main loop
while(1)
{
//Right now will never come out of this function (blocking on serial port)
netv_transceiver(canAddr);
update_variables();
}
In the same main.c file, you need to add several functions:
void netv_proc_message(NETV_MESSAGE *message)
{
//Handle custom messages...
}
void init_default_variables(void)
{
memset(&g_globalNETVVariables, 0, sizeof(GlobalNETVVariables));
}
For the [UControl] project, here is what it looks like:
void netv_proc_message(NETV_MESSAGE *message)
{
//Handle custom messages...
}
void init_default_variables(void)
{
memset(&g_globalNETVVariables, 0, sizeof(GlobalNETVVariables));
g_globalNETVVariables.FlashRate = REFRESH_RATE;
}
void update_variables(void)
{
//Misc.
REFRESH_RATE = g_globalNETVVariables.FlashRate;
g_globalNETVVariables.Count = TMR1L;
//Analog:
g_globalNETVVariables.Analog0 = adc_buffer[0];
g_globalNETVVariables.Analog1 = adc_buffer[1];
g_globalNETVVariables.Analog2 = adc_buffer[2];
g_globalNETVVariables.Analog3 = adc_buffer[3];
g_globalNETVVariables.Analog4 = adc_buffer[4];
g_globalNETVVariables.Analog5 = adc_buffer[5];
g_globalNETVVariables.Analog6 = adc_buffer[6];
g_globalNETVVariables.Analog7 = adc_buffer[7];
g_globalNETVVariables.Analog8 = adc_buffer[8];
g_globalNETVVariables.Analog9 = adc_buffer[9];
g_globalNETVVariables.Analog10 = adc_buffer[10];
g_globalNETVVariables.Analog11 = adc_buffer[11];
//Pre-computed analog values:
g_globalNETVVariables.Temp = adc_get_temp();
g_globalNETVVariables.Amp = adc_buffer[8] - 512;
}
Finally, you need to deal with incoming data in your ISR:
#pragma interrupt Interrupt_High
void Interrupt_High(void)
{
unsigned char sauv1;
unsigned char sauv2;
sauv1 = PRODL; // Save context
sauv2 = PRODH;
if(PIR1bits.RC1IF) //USART1 RX
{
//Handle USART Interrupt
serial_usart_interrupt_handler();
}
PRODL = sauv1; //Restore context
PRODH = sauv2;
}
#pragma code
Since there is no clear convention of registers and bits name for different PIC controllers, we need to customize the usart.c file for a specific project. The function names are fixed and should not be changed (the SerialDriver wouldn't know where to look).
Here is a typical usart.h file with function prototypes:
#ifndef INC_USART_H
#define INC_USART_H
void setup_usart1(void);
void putc_usart1(char data);
char getc_usart1(void);
char busy_usart1(void);
char datardy_usart1(void);
void puts_usart1(char *data);
void gets_usart1(char *buffer, unsigned char len);
#endif
In the usart.c file, you need to "fill" each function according to the datasheet. You can look in the Microchip's library for inspiration. Here is the file for the [UControl] project:
//Important: this code is strongly inspired from the C18 uart lib because for the moment
//the PIC18F44K22 isn't supported. Limitations: 8-bits only, no error check, usart1 only
//#include "def.h"
#include "usart.h"
#include "NETV8_Device.h"
void setup_usart1(void)
{
RCSTA1bits.SPEN = 1; //Disable serial port
TXSTA1bits.TX9 = 0; //8bits transmission
TXSTA1bits.TXEN = 1; //Enable transmit
TXSTA1bits.SYNC = 0; //Asynchronous
TXSTA1bits.BRGH = 1; //1 = High speed
RCSTA1bits.SPEN = 1; //Enable serial port
RCSTA1bits.RX9 = 0; //8bits reception
RCSTA1bits.CREN = 1; //Continuous reception
BAUDCON1bits.BRG16 = 0; //1 = 16bits
SPBRG1 = 51; //8 = 115200, 16 = 57600, 103 = 9600, 51 = 19200 @ 64MHz
PIE1bits.RC1IE = 1; //Enable interrupt on reception
RCSTA1bits.SPEN = 1; //Enable serial port
}
void putc_usart1(char data)
{
TXREG1 = data; //Write the data byte to the USART1
}
char getc_usart1(void)
{
return (RCREG1); // Return the received data
}
char busy_usart1(void)
{
if(!TXSTA1bits.TRMT) // Is the transmit shift register empty
return 1; // No, return FALSE
return 0; // Return TRUE
}
char datardy_usart1(void)
{
if(PIR1bits.RC1IF) // If RCIF is set
return 1; // Data is available, return TRUE
return 0; // Data not available, return FALSE
}
void gets_usart1(char *buffer, unsigned char len)
{
char i; // Length counter
unsigned char data;
for(i=0;i
The NETVx_Shared_project-name.h file contains the data structure GlobalNETVVariables that Network Viewer can read and write. Here is an example:
#ifndef _NETV8_SHARED_UCONTROL_H_
#define _NETV8_SHARED_UCONTROL_H_
#include "NETV8_Utils.h"
#define MODULE_TABLE_VERSION 0x02
#define MODULE_PROJECT_ID 0x01
#define MODULE_CODE_VERSION 0x01
typedef struct
{
uint16 FlashRate;
uint8 Count;
uint8 Free;
uint16 Analog0;
uint16 Analog1;
uint16 Analog2;
uint16 Analog3;
uint16 Analog4;
uint16 Analog5;
uint16 Analog6;
uint16 Analog7;
uint16 Analog8;
uint16 Analog9;
uint16 Analog10;
uint16 Analog11;
uint16 Temp;
sint16 Amp;
uint16 Volt1;
uint16 Volt2;
} GlobalNETVVariables;
#endif
The NETVx_Shared_project-name.c only is minimalist and only contains an include:
#include "NETV8_Shared_ucontrol.h"
For the moment the bsp.h file is simple and only contains some definitions:
#ifndef _BSP_UCONTROL_H_
#define _BSP_UCONTROL_H_
#include <p18f44k22.h>
#include "NETV8_Shared_ucontrol.h"
#define DEVID_BASE_ADDRESS 0x3FFFFE
#endif
Now that the PIC is programmed with the library, there is one last step to use it with Network Viewer: the XML config file. All the necessery information to write an application-specific file is on the [NetworkViewer] page. Here is an example:
<ModuleConfiguration moduleState="-1" deviceID="-1" projectID="1" codeVersion="-1" processorID="-1" tableVersion="-1" >
<ModuleVariable offset="0" description="Alive LED flash rate" type="uint16" value="" name="FlashRate" />
<ModuleVariable offset="2" description="Counter" type="uint8" value="" name="Count" />
<ModuleVariable offset="3" description="Unused" type="uint8" value="" name="Free" />
<ModuleVariable offset="4" description="Analog input 0" type="uint16" value="" name="Analog0" />
<ModuleVariable offset="6" description="Analog input 1" type="uint16" value="" name="Analog1" />
<ModuleVariable offset="8" description="Analog input 2" type="uint16" value="" name="Analog2" />
<ModuleVariable offset="10" description="Analog input 3" type="uint16" value="" name="Analog3" />
<ModuleVariable offset="12" description="Analog input 4" type="uint16" value="" name="Analog4" />
<ModuleVariable offset="14" description="Analog input 5" type="uint16" value="" name="Analog5" />
<ModuleVariable offset="16" description="Analog input 6" type="uint16" value="" name="Analog6" />
<ModuleVariable offset="18" description="Analog input 7" type="uint16" value="" name="Analog7" />
<ModuleVariable offset="20" description="Analog input 8" type="uint16" value="" name="Analog8" />
<ModuleVariable offset="22" description="Analog input 9" type="uint16" value="" name="Analog9" />
<ModuleVariable offset="24" description="Analog input 10" type="uint16" value="" name="Analog10" />
<ModuleVariable offset="26" description="Analog input 11" type="uint16" value="" name="Analog11" />
<ModuleVariable offset="28" description="Temperature" type="uint16" value="" name="Temp" />
<ModuleVariable offset="30" description="Current" type="sint16" value="" name="Amp" />
<ModuleVariable offset="32" description="Voltage channel 1" type="uint16" value="" name="Volt1" />
<ModuleVariable offset="34" description="Voltage channel 2" type="uint16" value="" name="Volt2" />
</ModuleConfiguration>