Archive
New CAN Main Board
I made a few adjustments to the board layout and also to the pcb-gcode setting and milled another circuit board. This one turned out nicely, even with a couple hiccups. First, the board wasn’t taped to the fixture exactly level, so a corner with nothing important didn’t mill through the copper (it was only the board outline). Then a phantom E-stop signal stopped the machine before it was done and had to restart from the beginning (I upped the debounce value to correct this). I thought it was another beverage coaster while watching it mill, but let it finish and it turned out fine. I ran the drill routine with a .035″ bit and everything but the screw terminal block and power jack fit. I was able to make the terminal block fit by sanding down the edges of the pins, but the power jack I’ll just use some wires and plug later.
Since the majority of components fit, I soldered this one up to give me an idea of what the next round of changes need to be. The main one is to increase the size of the pads to make it easier to solder and to increase the isolation path around them to prevent bridges to the ground plane. I’ll also have to change the through holes to the right size in the Eagle component library I made. At least the spacings were all right so everything still fit. Another change will be to the text ratio so the thin areas of copper don’t peel off when milled. They probably would have been fine if the second pass wasn’t done, but whatever.
Anyways, the CAN Main board only contains the basic circuit to run a 18F4580 micrcocontroller with the MCP2551 CAN transceiver; power from a 7805, 20MHz crystal oscillator, ICD plug, reset button, CAN status LED and then the rest of the pins are brought out to female headers to plug in a shield. I also included an area for the CAN bus termination resistor and three capacitors with jumpers, and a place to connect the cable shielding to the board’s ground. There is a jumper to bypass the 7805 regulator to use a 5V wall wart directly which are more common these days.
Microchip Graphics Library Integration
Here is some code for the eBay HX8347-A LCD I’ve been dinking with that utilizes the Graphics Library provided by Microchip. They have a few nice app notes on creating the graphical widgets on one of their development boards, but not really for a custom setup like my Commander32. All of their microcontrollers use the PMP feature to communicate with the LCD, while I just use pins directly. Their help file gives a nice summary of copying the library files to a new project to keep the file structure intact. Once that is done, the following steps should help make your own setup.
- Write a new HardwareProfile.h
Write from scratch to contain the definition of the LCD pins to the microcontroller pins and the clock frequency define for SYS_FREQ (required for library). This goes in source folder with your main.c file.
#define SYS_FREQ (80000000) // Definitions for reset pin #define RST_TRIS_BIT TRISGbits.TRISG12 #define RST_LAT_BIT LATGbits.LATG12 #define LCD_REST RST_LAT_BIT // Definitions for CS pin #define CS_TRIS_BIT TRISGbits.TRISG13 #define CS_LAT_BIT LATGbits.LATG13 #define LCD_CS CS_LAT_BIT // Definitions for RS pin #define RS_TRIS_BIT TRISGbits.TRISG15 #define RS_LAT_BIT LATGbits.LATG15 #define LCD_RS RS_LAT_BIT // Definitions for WR pin #define WR_TRIS_BIT TRISGbits.TRISG14 #define WR_LAT_BIT LATGbits.LATG14 #define LCD_WR WR_LAT_BIT // Definitions for WR pin #define RD_TRIS_BIT TRISDbits.TRISD9 #define RD_LAT_BIT LATDbits.LATD9 // Data Port for 16 bits #define LCD_DATA LATB #define LCD_DATA_TRIS TRISB #define DataPortIn() LCD_DATA_TRIS = 0xffff; #define DataPortOut() LCD_DATA_TRIS = 0x0000;
- Custom LCD Driver (HX8347A_16BIT.c &.h)
The Library contains some blank custom driver files (.c and .h in separate folders w/in library) with the two basic functions, DeviceReset() and PutPixel() required, but empty. My previous LCD initialization code was dumped into DeviceReset() and similarly with the PutPixel(). I also needed to write my own routines for ClearDevice() and Bar(), to optimize drawing. This required the appropriate lines in the header file to be uncommented to use these functions over the Library’s.
HX8347A_16BIT.c
/*****************************************************************************
* Module for Microchip Graphics Library
HX8347 LCD Controller
* Custom display controller driver template
* By: Ryan Milewski, 2012
*****************************************************************************/
#include "Graphics/Graphics.h"
#include "HardwareProfile.h"
// Color
WORD_VAL _color;
// Clipping region control
SHORT _clipRgn;
// Clipping region borders
SHORT _clipLeft;
SHORT _clipTop;
SHORT _clipRight;
SHORT _clipBottom;
/*********************************************************************
* Function: void DelayMs(WORD time)
* PreCondition: none
* Input: time - delay in ms
* Output: none
* Side Effects: none
* Overview: delays execution on time specified in ms
* Note: none
********************************************************************/
void DelayMs(unsigned int msec)
{
unsigned int tWait, tStart;
tWait=(SYS_FREQ/2000)*msec;
tStart=ReadCoreTimer();
while((ReadCoreTimer()-tStart)<tWait); // wait for the time to pass
}
void LCD_write_COM(WORD data)
{
LCD_RS = 0;
LCD_CS = 0;
LCD_DATA = data;
LCD_WR = 0;
//Nop();
//Nop();
//Nop();
LCD_WR = 1;
LCD_CS = 1;
}
void LCD_write_DATA(WORD data)
{
LCD_RS = 1;
LCD_CS = 0;
LCD_DATA = data;
LCD_WR = 0;
//Nop();
//Nop();
//Nop();
LCD_WR = 1;
LCD_CS = 1;
}//end of WriteLCD_DATA()
void LCD_write_COM_DATA(BYTE index, WORD value)
{
LCD_write_COM(index);
LCD_write_DATA(value);
}
/*********************************************************************
* Function: void ResetDevice()
* PreCondition: none
* Input: none
* Output: none
* Side Effects: none
* Overview: resets LCD, initializes PMP
* Note: none
********************************************************************/
void ResetDevice(void)
{
// Set uController pins TRIS
AD1PCFG = 0xffff; //analog pins all digital
CS_TRIS_BIT = 0;
RS_TRIS_BIT = 0;
WR_TRIS_BIT = 0;
RD_TRIS_BIT = 0;
DataPortOut();
//Reset LCD
LCD_REST = 1;
DelayMs(5); //5ms delay
LCD_REST = 0;
DelayMs(10); //10ms delay
LCD_REST = 1;
DelayMs(20); //20ms delay
//Vendor gamma
LCD_write_COM_DATA(0x0046,0x00a4);
LCD_write_COM_DATA(0x0047,0x0053);
LCD_write_COM_DATA(0x0048,0x0000);
LCD_write_COM_DATA(0x0049,0x0044);
LCD_write_COM_DATA(0x004a,0x0004);
LCD_write_COM_DATA(0x004b,0x0067);
LCD_write_COM_DATA(0x004c,0x0033);
LCD_write_COM_DATA(0x004d,0x0077);
LCD_write_COM_DATA(0x004e,0x0012);
LCD_write_COM_DATA(0x004f,0x004c);
LCD_write_COM_DATA(0x0050,0x0046);
LCD_write_COM_DATA(0x0051,0x0044);
//240x320 window settings
LCD_write_COM_DATA(0x0002,0x0000); //Column address start2
LCD_write_COM_DATA(0x0003,0x0000); //column address start1
LCD_write_COM_DATA(0x0004,0x0000); //Column address end2
LCD_write_COM_DATA(0x0005,0x00ef); //Column address end1
LCD_write_COM_DATA(0x0006,0x0000); //Row address start2
LCD_write_COM_DATA(0x0007,0x0000); //Row address start1
LCD_write_COM_DATA(0x0008,0x0001); //Row address end2
LCD_write_COM_DATA(0x0009,0x003f); //Row address end1
//display settings
LCD_write_COM_DATA(0x0001,0x0006); //IDMON=0,INVON=1,NORON=1,PTLON=0
LCD_write_COM_DATA(0x0016,0x0078); //MY=0,MX=0,MV=0,ML=1,BGR=0,TEON=0
LCD_write_COM_DATA(0x0023,0x0095); //N_DC=1001 0101
LCD_write_COM_DATA(0x0024,0x0095); //PI_DC=1001 0101
LCD_write_COM_DATA(0x0025,0x00ff); //I_DC=1111 1111
LCD_write_COM_DATA(0x0027,0x0002); //N_BP=0000 0010
LCD_write_COM_DATA(0x0028,0x0002); //N_FP=0000 0010
LCD_write_COM_DATA(0x0029,0x0002); //PI_BP=0000 0010
LCD_write_COM_DATA(0x002a,0x0002); //PI_FP=0000 0010
LCD_write_COM_DATA(0x002c,0x0002); //I_BP=0000 0010
LCD_write_COM_DATA(0x002d,0x0002); //I_FP=0000 0010
LCD_write_COM_DATA(0x003a,0x0001); //N_RTN=0000,N_NW=001
LCD_write_COM_DATA(0x003b,0x0000); //P_RTN=0000,P_NW=001
LCD_write_COM_DATA(0x003c,0x00f0); //I_RTN=1111,I_NW=000
LCD_write_COM_DATA(0x003d,0x0000); //DIV=00
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x0035,0x0038); //EOS=38h
LCD_write_COM_DATA(0x0036,0x0078); //EQP=78h
LCD_write_COM_DATA(0x003e,0x0038); //SON=38h
LCD_write_COM_DATA(0x0040,0x000f); //GDON=0fh
LCD_write_COM_DATA(0x0041,0x00f0); //GDOFF
//Power Supply Settings
LCD_write_COM_DATA(0x0019,0x0049); //CADJ=0100,CUADJ=100,OSD_EN=1,60Hz
LCD_write_COM_DATA(0x0093,0x000f); //RADJ=1111, 100%
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x0020,0x0040); //BT=0100
LCD_write_COM_DATA(0x001d,0x0007); //VC1=111
LCD_write_COM_DATA(0x001e,0x0000); //VC3=000
LCD_write_COM_DATA(0x001f,0x0004); //VRH=0011
//VCOM Settings
LCD_write_COM_DATA(0x0044,0x004d); //VCM=101 0000
LCD_write_COM_DATA(0x0045,0x000e); //VDV=1 0001
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x001c,0x0004); //AP=100
DelayMs(2); //2ms delay
LCD_write_COM_DATA(0x001b,0x0018); //GASENB=0,PON=1,DK=1,XDK=0,VLCD TRI=0,STB=0
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x001b,0x0010); //GASENB=0,PON=1,DK=0,XDK=0,VLCD TRI=0,STB=0
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x0043,0x0080); //set VCOMG=1
DelayMs(2); //2ms delay
//Display On Setting
LCD_write_COM_DATA(0x0090,0x007f); //SAP=0111 1111
LCD_write_COM_DATA(0x0026,0x0004); //GON=0,DTE=0,D=01
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x0026,0x0024); //GON=1,DTE=0,D=01
LCD_write_COM_DATA(0x0026,0x002c); //GON=1,DTE=0,D=11
DelayMs(1); //1ms delay
LCD_write_COM_DATA(0x0026,0x003c); //GON=1,DTE=1,D=11
//Internal Register Settings
LCD_write_COM_DATA(0x0057,0x0002); //TEST_Mode=1: into test mode
LCD_write_COM_DATA(0x0095,0x0001); //SET DISPLAY CLOCK AND PUMPKING CLOCK TO SYCRONIZE
LCD_write_COM_DATA(0x0057,0x0000); //TEST Mode=0:exit TEST Mode
LCD_write_COM(0x0022);
}
void LCD_address_set(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
{
LCD_write_COM_DATA(0x0002,x1>>8); //Column address start2
LCD_write_COM_DATA(0x0003,x1); //Column address start1
LCD_write_COM_DATA(0x0004,x2>>8); //column address end2
LCD_write_COM_DATA(0x0005,x2); //column address end1
LCD_write_COM_DATA(0x0006,y1>>8); //Row address start2
LCD_write_COM_DATA(0x0007,y1); //row address start1
LCD_write_COM_DATA(0x0008,y2>>8); //row address end2
LCD_write_COM_DATA(0x0009,y2); //row address end1
LCD_write_COM(0x0022);
}
/*********************************************************************
* Function: void PutPixel(SHORT x, SHORT y)
* PreCondition: none
* Input: x,y - pixel coordinates
* Output: none
* Side Effects: none
* Overview: puts pixel
* Note: none
********************************************************************/
void PutPixel(SHORT x, SHORT y)
{
unsigned int ncolor;
ncolor = GetColor();
LCD_address_set(x,y,x,y);
LCD_write_DATA(ncolor);
}
/*********************************************************************
* Function: WORD GetPixel(SHORT x, SHORT y)
* PreCondition: none
* Input: x,y - pixel coordinates
* Output: pixel color
* Side Effects: none
* Overview: returns pixel color at x,y position
* Note: none
********************************************************************/
WORD GetPixel(SHORT x, SHORT y)
{
return (0);
}
/*********************************************************************
* Function: void ClearDevice(void)
* PreCondition: none
* Input: none
* Output: none
* Side Effects: none
* Overview: clears screen with current color and sets cursor to 0,0
* Note: none
********************************************************************/
void ClearDevice(void)
{
int i,j;
unsigned int ncolor;
ncolor = GetColor();
LCD_address_set(0,0,DISP_HOR_RESOLUTION-1,DISP_VER_RESOLUTION-1);
for(i=0;i<DISP_HOR_RESOLUTION;i++)
{
for(j=0;j<DISP_VER_RESOLUTION;j++)
{
LCD_write_DATA(ncolor);
}
}
}
/*********************************************************************
* Function: WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
* PreCondition: none
* Input: left,top - top left corner coordinates,
* right,bottom - bottom right corner coordinates
* Output: For NON-Blocking configuration:
* - Returns 0 when device is busy and the shape is not yet completely drawn.
* - Returns 1 when the shape is completely drawn.
* For Blocking configuration:
* - Always return 1.
* Side Effects: none
* Overview: draws rectangle filled with current color
* Note: none
********************************************************************/
WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
{
unsigned ncolor;
int i,j;
ncolor = GetColor();
LCD_address_set(left,top,right,bottom);
for(i=0;i<=(right-left);i++)
{
for(j=0;j<=(bottom-top);j++)
{
LCD_write_DATA(ncolor);
}
}
return (1);
}
- Select options in GraphicsConfig.h
This should be copied from Microchip and placed in your project folder (like the help file says). Put in the Horizontal and Verticle resolution defines your LCD and uncomment the Graphics options to be used.
- Replace DeviceDriver.h with Custom Driver
There are two Library files that need to be changed to use the custom driver in the #includes; Primitive.c and Graphics.h. In my case, #include “DeviceDriver.h” was replaced with “HX8347A_16BIT.h”.
Primitive.c
#include "HardwareProfile.h" // needed to provide values for GetMaxX() and GetMaxY() macros #include "HX8347A_16BIT.h" //Change to custom driver header HERE!! #include "Graphics/Primitive.h" #include "Compiler.h"
Then,
Graphics.h
////////////////////////////// INCLUDES //////////////////////////////
#include <stdlib.h> // needed because of malloc()
#include "GenericTypeDefs.h"
#include "GraphicsConfig.h"
#include "HX8347A_16BIT.h" // Display Driver layer
#include "Primitive.h" // Graphic Primitives layer
#include "GOL.h" // Graphics Object layer
At this point, the Library’s Primitive Layer can be tested. I just grabbed some example code to draw the basic shapes available, text, and some images. Yay!
- Custom Touchscreen Driver
The files Touchscreen.c and.h were copied to my project folder and renamed ADS7843Touchscreen.c and .h for customizing. Microchip’s dev boards all drive the touch screen using the ADC, but mine uses the ADS7843 chip which takes care of all that. I kept the function TouchGetMsg() which processes the touch actions into predefined states, and added my own code for initializing and TouchGetXY(). My function gets both x and y coordinates at the same time and needed multiple readings of each and averaged to reduce noise. The ADS7843 has a convientent PenIRQ pin to signal an actual touch or an Idle condition (x = -1,y = -1).
ADS7843Touchscreen.c
SHORT touchX,touchY;
void spistart(void)
{
D_CS = 1;
D_CLK = 1;
D_DIN = 1;
}//end of spistart()
void ADS7843_write(unsigned char num)
{
unsigned int count,mask,temp;
int i;
D_CLK = 0;
mask = 0x80;
for(count=0;count<8;count++)
{
temp = mask#
if (temp == 0) D_DIN = 0;
else D_DIN = 1;
//D_DIN = temp>>(count);
D_CLK = 0;
for(i=0;i<5;i++)
{
Nop();
}
D_CLK = 1;
for(i=0;i<5;i++)
{
Nop();
}
mask>>=1;
}
}//end of ADS7843_write()
unsigned int ADS7843_read(void)
{
unsigned int count;
unsigned int num;
int i;
num = 0;
for(count=0;count<12;count++)
{
num<<=1;
D_CLK = 1;
for(i=0;i<5;i++)
{
Nop();
}
D_CLK = 0;
for(i=0;i<5;i++)
{
Nop();
}
if(D_DOUT) num++;
}
return(num);
}//end of ADS7843_read()
void TouchInit(void)
{
//Port Init
D_CLK_TRIS = 0;
D_CS_TRIS = 0;
D_DIN_TRIS = 0;
D_DOUT_TRIS = 1;
D_IRQ_TRIS = 1;
spistart();
}
void TouchGetXY(void)
{
int i,count,x_set,y_set;
int TP_X,TP_Y;
count =0;
x_set = 0;
y_set = 0;
while(count<8)
{
//PORTAbits.RA1 = 1;
//Delay1KTCYx(4); //2ms delay (8MHz clk)
D_CS = 0;
ADS7843_write(0xd4);
D_CLK = 1;
for(i=0;i<5;i++)
{
Nop();
}
D_CLK = 0;
for(i=0;i<5;i++)
{
Nop();
}
y_set = y_set + ADS7843_read();
count++;
}
count = 0;
while(count<16)
{
ADS7843_write(0x94);
D_CLK = 1;
for(i=0;i<5;i++)
{
Nop();
}
D_CLK = 0;
for(i=0;i<5;i++)
{
Nop();
}
x_set = x_set + ADS7843_read();
count++;
}
D_CS = 1;
TP_X = x_set/16;
TP_Y = y_set/8;
touchX = .0925*TP_X-.0040*TP_Y-31.1315; //X-coordinate
touchY = .0006*TP_X+.0661*TP_Y-19.5759; //Y-coordinate
}
SHORT TouchGetX(void)
{
int x;
x = touchX;
return(x);
}
SHORT TouchGetY(void)
{
int y;
y = touchY;
return(y);
}
int TouchIRQ(void)
{
int temp;
temp = D_IRQ;
return(temp);
}
Those functions will interact with Microchip’s TouchGetMsg(), and only needs ads7843touchscreen.h included in the main .c file source.
- Add required main() code
A little bit of code needs to be added to the main() while loop, which is shown more than once in a Microchip app note. Also a data structure, GOL_MSG msg, to relay events needs to be cast.
So hopefully your project is going. Adding and interacting with the widgets is pretty straight forward and documented in the help file (you should have been there already). I had several issues along the way, such as:
- The default font. Solution: use Font25 or Font35 and cast correctly.
- Start with the newest version 3 something, drastic changes were made and things didn’t work.
- While developing touch screen driver, the data wasn’t being transferred to the rest of the GOL, so the widgets wouldn’t draw as pushed. Solution: start new project completely with same drivers. ?????
CAN Code for Initialization
Here’s some code to get going. The ECAN section of the 18F4580 datasheet describes the modules function and how to use it, so I’ll only briefly describe what’s going on.
To write to certain ECAN configuration registers, you must request to enter a Config mode, then wait for the module to enter it. The Baud rate settings are tricky, but can be found easily from here, Request form for CANopen Bit Timings. Only one Receive Filter is used and linked to Receive Buffer 0. To add more Enable the filter in RFCONx, associate to a Receive buffer with RXFBCONx, then set its identifier. Last is to exit the Config mode by requesting either Normal mode or Loopback mode for testing. An important point here is that the ECAN module won’t exit config mode unless the microcontroller is correctly connected to a CAN driver IC, even for going to Loopback mode.
void ECAN_Init(void)
{
LATB = 0x00;
TRISBbits.TRISB3 = 1;
CANCON = 0x80; //request CONFIG mode
while(CANSTATbits.OPMODE2==0);
ECANCON = 0x40; //Sets ECAN to Mode 1
BRGCON1 = 0x09; //Sets Baud rate
BRGCON2 = 0x84;
BRGCON3 = 0x00;
BSEL0 = 0xfc;
RXM0EIDH = 0x00; // 0's for EID and SID
RXM0EIDL = 0x00;
RXM0SIDH = 0xFF; // Standard ID FILTER
RXM0SIDL = 0xE0; //Mask0 = 0x7ff
RXFCON0 = 0x01; //filter 0 enabled
RXFCON1 = 0x00; //all others disabled
MSEL0 = 0xfc; //Mask0 assigned to Filter0
MSEL1 = 0xFF; //all others no mask
MSEL2 = 0xFF;
MSEL3 = 0xFF;
RXFBCON0 = 0x00; //filter 0 assoc w/ RXB0, 1 w/ RXB1
RXB0CONbits.RXM1 = 1;
RXF0SIDH = 0x04; //Recv Filter0 = 0x020
RXF0SIDL = 0x00; //Std. Identifier
RXF0EIDH = 0x00;
RXF0EIDL = 0x00;
CANCON = 0x00; //Set ECAN to normal mode
//CANCON = 0x40; //Set ECAN to Loopback mode(TEST)
while(CANSTATbits.OPMODE2 == 1); //wait till out of Config Mode
}//end of ECAN_Init()
When setting up a test bus, start with one node set in Loopback mode. In this mode, the acknowledge bits are ignored and allows the node to receive CAN messages transmitted from itself.This will confirm the baud and filter settings are correct. I made a loop of sending and receiving with counters, then displaying on an LCD(nokia 6100). Once I had my two breadboards able to send and receive the same number of messages, I connected them together. Of course the micrcontroller must be connected to a CAN driver IC, the MCP2551, with a 60Ω resistor connected between the CANH and CANL pins, or the module would never get out of config mode.
The datasheet describes how to transmit a message, and doesn’t need any extra configuration. To receive a message, the ECAN module will accept and place data in the proper register, then set a flag that can be polled. An interrupt can be used too.
Hopefully this helps get others going. Later.
CAN Nodes for Smart House
Good news everyone! I got two working CAN nodes that I hope to use for setting up a smart house network. I want to outfit my house with sensors and controls for various tasks such as data logging, HVAC control and as a reminder to not leave doors open all night. In a nutshell, CAN is a communication protocol first used in automobiles and more info is here. It’s features include collision detection, operation in noisy environment and being a single twisted-pair wire for easy install(I hope).
So far my two nodes both use the PIC 18F4580 microcontroller and MCP2551 CAN bus Driver, but different peripherals. The CAN engine built into the 18F4580 takes care of the bulk of the CAN protocol, like bit-stuffing, masks and filters, the different frames and all the other goodies in the spec. I had a class a couple years ago that covered it all and some other stuff that is already replacing CAN, so I didn’t actually read it(ha!). Anyways, the basic communications are demoed with the two nodes, press a button on Node1 to send a message to Node2, and Node2 periodically requests data from Node1 (a temperature sensor). This is my mock-up for the first phase of the smart house when I replace my ancient doorbell system of cloth-clad, solid wire to the twisted pair CAN bus, then expand by adding nodes.
As far as schematics and code, they are works in progress and yet to be released. I have a Sensor node schematic and board almost done, then an LCD/Info node following. As far as the code is concerned, I was disappointed in the Microchip ECAN Library, and found loading the appropriate registers following the datasheet to be easier. This was also the general theme coming from Microchip’s CAN forum. Also I’m getting a git hub together to share, so yeah.
Introducing the Commander32
Hi-dilly-ho neglete-arino, I mean blog. I’ve put together a new microcontroller setup after the previous one was too slow at calculating fractals.
This new setup, dubbed the Commander32, consists of a Pic32 Starter Kit, eflighworks companion board(barebones w/ socket, I added the rows of headers) and an HX8347 controlled 3.2″ TFT LCD from eBay. The code for the previous 18F controller ported easily, once switching to writing to the ports with the LATx registers instead of the usual PORTx. Since Port B is 16-bits wide, this was connected directly to the LCD data pins, and made programming even easier. The remaining four control pins were connected to the upper bits of Port G, that didn’t have any other peripheral features. I might switch the data pins to use the PMP feature to free up the analog pins on port B.
The touchscreen is also working, and improved. An app note on calibration from Ti showed how to use a couple matrices to generate the conversion equation coefficients. It was easiest to solve with Matlab, instead of expanding manually and having the microcontroller crunch the numbers. The next issue was the considerable noise in the x direction, causing one point to stretch to a little line. This was fixed by taking multiple readings, then averaging. So now I plenty of pins and speed to use the sd memory socket on the LCD board, plus a wireless device and some sensors or something. Porting the code was easy enough, and was more of finding the tricks for the Starter Kit, like what pins not to use with debugging. Maybe I’ll build a micro-touch-circuit-thing, and call it iTouchMyself.
Indoor Garden Update – Basic Microcontroller Circuit
Good news everyone, another step completed in my window garden. This is just a plain PIC 16F877A microcontroller with a 20MHz resonator and a character LCD. There is also a big photo-resistor for shits and giggles and some neat buttons. I got a dual relay board from eBay to turn the pump on and off, and an extra socket for a light down the road.
Inside the outlet box and wall plate I gussied up are the 120V mains. After triple checking with a multimeter and several websites, I made sure the neutral and hot sides of the plug were wired correctly. Neutral being white, the widest blade of the plug and silver tab on the socket. The hot, black side is switched and is the brass tab. To have the two sockets independent, clip the jumper between the hot side only.
So far, this is an overly complicated setup to turn one thing on and off occasionally. I’m working on my own version of a soil moisture sensor (I wasn’t too happy with the plaster version). Then I was thinking of using it as a Neural network experiment to learn to control itself using a variety of data.
Touchscreen Buttons & Sliders
Hey, I’m back. This time I’m posting my code for getting the hex color values for RGB combos. Mainly, it’s just some experimenting with the touchscreen to create a user interface for the microcontroller. In the past, it was either buttons, pots or rotary encoders and one would have to be crafty to use as little as pins possible for the greatest number of inputs. Now, its just a matter of defining an area with ifs and else ifs and being bounded within the LCD.
The RGB controller uses six buttons and three sliders. Here’s the main file; rgb controller.c. I figure it’ll be useful to define different shades of colors than just the standard RED, BLUE and GREEN. I updated the lcd code with a bar graph function for the slide controls, so you’ll need that;320×240 LCD.c & 320×240 LCD.h. The touchscreen code is the same as before.
Touchscreen Code for ADS7843
Here’s my code for the touchscreen. It’s basically just ported from whatever was provided, with a slightly improved painting application. The coordinate conversion could use some tweaking, but is close enough for now. Using integers saves code space anyways. The Y direction is kinda jumpy too, and could probably be fixed with different settings. Meh, later…
The main file is pic paint; the driver for the touchscreen is ADS7843 header and ADS7843 driver. The LCD uses the code posted previously.
HX8347-A LCD Code for PIC18F4580
Here’s my code, at long last. It just does text and basic drawing, no support for pictures or bitmaps yet. The main file, tft lcd test.c shows examples of the functions from the two files lcd320x240.h and .c. Until I can put up .zip files, I’ll have to used Word…
Gardening with Microcontrollers
Yay, spring is finally here and it’s time to start planting things. That way I’ll have something to neglect when its hot as hell or something for the squirrels to dig up. Which ever kills the plants first.
No, this year will be different. I’m going to harness the power of microcontrollers to; A) keep plants watered and B) Stop animals from destroying anything is growing.
I already have an outside area for growing some crops, but I also want something inside for fresh herbs year-round. So I’ll have two different areas to monitor and control. In both places I’ll monitor the soil moisture with some DIY sensors with the intent of automated watering.
The herbs will hang in the kitchen windows and use 2 liter pop bottles for growing chambers, which I built a couple months ago. Only weeds grew, but this trial run allowed me to sort out draining issues before real plants grew. Also, my first attempt at sensors failed. Here’s a new batch after a little googling.
Outside, I’m going to modify a plastic owl I bought last year. Needless to say it didn’t do the job, so I thought some flashing LED eyes and a lot of noise will change that. I’m not sure what kind of sensor detects treacherous squirrels, maybe a motion detector, or a series of lasers…
Anyways, this project has many components and will be a miracle if it’s completed. I think I’ll make a permanent page for the entire system once it’s something something operational.















