Jump to content

DavidT

EstablishedMember
  • Content Count

    60
  • Joined

  • Last visited

Posts posted by DavidT


  1. Hi. If you are using normal servos then they will be expecting a pulse of between 1 and 2ms every 20ms. I'd guess your two controls are aileron (or rudder) and elevator. They don't need to be operated exactly together so you can simply make servo1 go high for between 1 and 2ms then low, then do the same for servo2. Then wait about 17ms and start again. The 1-2ms is important but the 20ms timing is not. You might be able to do this with delays, or otherwise just wait for a 16bit timer to reach appropriate values before making ports high/low.

     

    If your motor control is via a commercial electronic speed control it will be expecting the same signal. So you can simply tag this on after servo1 and 2 and reduce the delay before starting the next cycle. This 'sequential' approach will work with up to 10 devices.

     

    Clearly you will need a whole bunch of logic to convert pitch and roll movements picked up by your accelerometers into servo instructions.

    Regards, David.


  2. I use the approach in post 7 but with reference diodes instead of zeners. These can be extremely accurate. Farnell sometimes have them in 10v although 5v and less are more common.

     

    I have 2 examples on my site. Follow the 'back' button at the foot of both pages. This will take you to a circuit description which explains how I use them.

    http://www.flyelectric.ukgateway.net/bal3-cct.htm

    http://www.flyelectric.ukgateway.net/lithtester2-cct.htm

     

    Regards, David.


  3. I'm not sure if PicKit2 does low voltage programming but it definitely does high voltage (the manual refers to a 12v Vpp). No mods are needed to the programmer. The config I gave you works perfectly on a default install of PicKit2.

     

    It is normal to link the Pic's MCLR pin to Vdd with a 10k resistor to prevent a floating input and random resets. While you are struggling, make sure nothing else is connected to the MCLR, PGD or PGC pins as extra circuitry can interfere with programming, especially the clock pin.

    dt.


  4. I've used the following successfully on a 16F88 (when looking up these settings in the data sheet note that Fosc uses bits 4, 1 and 0; can be confusing):

    #pragma DATA 0x2007, 0b11111101010000	//Config1
    #pragma DATA 0x2008, 0b00				//Config2

     

    I recall reading about a special low voltage setting which can be used to recover Pics. You'll need to troll through some of the posts: http://forum.microchip.com/tt.aspx?forumid=15

     

    David.


  5. An old project would not compile. Displayed "Building..." at the bottom and nothing else.

     

    I installed it to a '685' folder and my previous version was to a '683' folder. When I looked at Settings/Options/Tools the Compiler&Link Directory field had defaulted to C:\Program Files\SourceBoost683\ I've had to change this manually to my new directory. I don't remember having to do this before.

    David.


  6. 1. Can you create a list of 'favourite' devices perhaps at the top of the Target drop down list. I'm sure most of us use a very small number of devices.

     

    2. To maximise the size of the main editing panel, can you reduce the rows taken to display key messages at the end of the Output window. I like to see the 3 'Memory Usage Report' rows but would then like one more row that says something like "Successful but with 'x' warning messages/'y' errors". I then know whether to scroll up or not.

     

    'Done' is redundant I think and the empty rows at the end are waste of space (empty rows higher up are OK to improve presentation). The two rows with the path are not useful to me but if they have a purpose perhaps put them slightly higher so I can adjust the window size to hide that info.

     

    Thanks, David.


  7. Thanks, this gives me more function orientated approaches and improvements. Is there any way to use an array or bits in a variable with each representing LED ports? I would like to switch the LEDs in a loop such as below. I can go with a function if necessary; I would just prefer to avoid the code overhead it seems to impose.

    David.

    if(i=0; i<3; i++)
    {
    led_function(i,1);		//Switch LEDs on via function
    led_array[i]=1;			//Use an array?
    set_bit(led_variable,i);	  //Bits in a variable?
    }


  8. Hi folk,

    I would like switch LEDs and FETs on and off in loops. I can define them individually but then I have to specify each every time. I can also set up a function and call that (see below) but this seems to increase code size. Are there better ways please?

    Thanks, David.

    void led (char num, bit state)		//Function to switch LEDs
    								//'num' is LED number
    								//'state' is 1=on, 0=off
    {
    if(num==1 && state==0) 		portc.4=0;	//LED1
    else if(num==1 && state==1) portc.4=1;
    
    else if(num==2 && state==0) porta.5=0;   //LED2
    else if(num==2 && state==1) porta.5=1;
    }


  9. I've written a program to measure individual cells in a pack and display graphs on a graphic LCD. I'm using an 18F2523 and BoostC 6.81. I want to perform 96 measurement cycles and am storing these ultimately in 5 fairly large arrays (log1-5), 1 for each cell. When these arrays and the code that populates them (in main and log_highlow) are where I have them in the code below, the PIC is unstable. By this I mean it either works as expected, displays nothing, scrambles some or all characters, responds to interrupts or not, etc. Packs with different voltages yield different behaviour. When I comment the highlighted sections out and put the 'log' arrays and code in the same function (display_graph) it is stable irrespective of the voltage inputs. The Interrupts are removed so they are not the cause.

     

    Looking at other posts I see people experience problems sometimes with variables being over-written, etc. I don't know how to check for this but do believe I've narrowed down the area cause instability. I suspect the log arrays. Can anyone suggest how to proceed please? I've tried to reduce the code to what it needs to demonstrate the problem but sorry it is still so long. I suspect you only need to look at the sections marked with hashes.

     

    As a side issue the log_highlow function produces 1194 words of code which seemed a lot to me.

    Thanks, David.

     

    #include <system.h>			//Generic device include (actual device set in Settings/Target)
    #include <stdlib.h>			//Needed for Integer to ASCII conversion (uitoa)
    
    //Core configuration (some commented out to leave at default):
    #pragma DATA 0x300001, 0b1000		//Config1H: Internal oscillator with IO on RA6 and 7
    #pragma DATA 0x300002, 0b11110		//Config2L: Brownout min voltage, hardware only, Powerup timer ON
    #pragma DATA 0x300003, 0			//Config2H: Watchdog timer DISabled
    #pragma DATA 0x300006, 0b10000001	//Config4L: Debug, Extended instructions and low volt pmg OFF
    #pragma DATA 0x30000A, 0b1100		//Config6L: Write protect Blocks 0 & 1 ENabled, 2 & 3 disabled
    #pragma DATA 0x30000B, 0b10000000	//Config6H: Write protect Boot and Config ENabled, EEPROM disabled
    
    //VARIABLES and DEFINITIONS ====================================================
    
    #define data	latc			//Defines Latch C as 'data' for writing to LCD via Port C (8 data lines)
    #define status	portc			//Defines Port C as 'status' for reading the port
    #define rs 		porta.6			//Defines RS / RI (data/instruction) pin
    #define rw 		porta.7			//Defines R/W read write pin
    #define menu	portb.0			//Defines Menu pushbutton (uses 'mode' flags in prgram)
    #define select	portb.1			//Defines Select pushbutton (uses 'sel' flags in prgram)
    #define en		portb.5			//Defines Enable pin
    #define cs1		portb.6			//Defines chip select 1 (left) - low to select
    #define cs2		portb.7			//Defines chip select 2 (right)
    
    typedef unsigned char 	u8;		//Defines u8 as an unsigned char type (8bits)
    typedef signed   char	s8;		//Defines s8 as an signed char type (8bits)
    typedef unsigned int	i16;	//Defines i16 as an unsigned short integer (16bits)
    typedef unsigned long 	u32;	//Defines u32 as an unsigned long type (32bits)
    
    //##############################################################################
    //Program is eratic when this is here - works when in display_lcd()
    
    i16	log1[97];			//Stores measurements for cell 1 etc...
    i16	log2[97];
    i16	log3[97];
    i16	log4[97];
    i16	log5[97];
    
    //##############################################################################
    
    i16	log_high[6];		//Highest value measured for cell 1 etc
    i16	log_highest;		//Highest value of all cells
    i16	log_low[6];			//Lowest for cell
    i16	log_lowest;			//Lowest of all cells
    
    u32	adc_result[8];		//Cummulative results of AD conversions for each cell
    
    u8	graph[] = {										//'Library 4' for LCD fonts
    0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,	//0-7	Lowest to highest graph dots
    0x00,											//8		Space (1 pixel)
    0xFF											//9		| (all vertical dots on)
    };
    
    u8	graph1[] = {									//'Library 5' for LCD fonts
    0x3e,	0x51,	0x49,	0x45,	0x3E,	0x00,	// 0
    0x00,	0x04,	0x02,	0x7F,	0x00,	0x00,	// 1
    0x62,	0x51,	0x49,	0x49,	0x46,	0x00,	// 2
    0x22,	0x41,	0x49,	0x49,	0x36,	0x00,	// 3
    0x18,	0x14,	0x12,	0x7F,	0x10,	0x00,	// 4
    0x4F,	0x49,	0x49,	0x49,	0x31,	0x00,	// 5
    0x3E,	0x49,	0x49,	0x49,	0x32,	0x00,	// 6
    0x03,	0x01,	0x61,	0x19,	0x07,	0x00,	// 7
    0x36,	0x49,	0x49,	0x49,	0x36,	0x00,	// 8
    0x26,	0x49,	0x49,	0x49,	0x3E,	0x00,	// 9
    0x00,	0x36,	0x36,	0x00,	0x00,	0x00,	// :
    0x14,	0x7F,	0x14,	0x7F,	0x14,	0x00,	// #
    0x00,	0x00,	0x60,	0x60,	0x00,	0x00,	// .
    0x7F,	0x09,	0x09,	0x09,	0x7F,	0x00,	// A
    0x00,	0x00,	0x3F,	0x40,	0x40,	0x00,	// l
    0x7F,	0x02,	0x04,	0x02,	0x7F,	0x00,	// M
    0x46,	0x49,	0x49,	0x49,	0x31,	0x00,	// S
    0x00,	0x00,	0x00,	0x00,	0x00,	0x00	// Space
    };
    
    i16	result;				//Merges ADC high and low registers
    u32	convert;			//Used in converting ADC values to volts
    
    u8	h_addr;				//Horizontal address (0-127) - must start at 0 for each new row
    u8	v_addr;				//Vertical address (0-7)
    u8	s_addr;				//Scroll address (0-64)
    
    u8	mode;				//Current 'Menu' selected
    u8	mode_min;			//Smallest menu option
    u8	mode_max;			//Largest menu option
    
    u8	sel;				//Current 'Select' option
    u8	sel_min;			//Smallest selection option
    u8	sel_max;			//Largest selection option
    
    u8	pack_size;			//Size of pack set in Mode 1; computes/displays all cells up to this number
    u8	pack_log;			//Number of cells actually logged in Mode 2
    u8	cell_num;			//Individual cell (singlar) set in Mode 2; 0 represents all measured
    
    void lcd_coord();						//Sets LCD co-ordinates
    void lcd_font (u8 library, u8 offset);	//Selects fonts from libraries and advances h_addr
    void lcd_write (u8 send, u8 mode);		//Sends characters and commands to LCD
    void lcd_refresh();						//Clears LCD
    
    void adc (u8 cells);					//Performs AD conversions, sums results; called by...
    void measure_cells (i16 iter);			//Initialisation and triggering of cell measurements
    
    void volts_calc (u8 cell, i16 iter);	//Cell-specific conversion arithmetic called by...
    void volts_pack (i16 iter);				//Conversion of ADC value to Volts
    
    void log_highlow ();					//Determines highest and lowest values
    void display_graph ();					//Displays graph on LCD
    
    
    //FUNCTIONS section ===========================================================
    
    void lcd_coord ()		//Function to establish co-ordinates
    					//'h_addr' selects horizonal address 'Y' (0-127)
    					//'v_addr' selects vertical / page address 'X' (0-7)
    					//Chip is selected automatically
    {
    u8	addr;
    
    if(h_addr<64)					//Address is on Left chip (1st 64 addresses 0-63)
    {
    	cs1=0; cs2=1;						//Configure left chip
    
    	addr = 0b01000000 + h_addr;			//Horizontal address command + 0-63
    	lcd_write(addr,0);					//Send instruction to LCD
    
    	addr = 0b10111000 + v_addr;			//Vertical address command + 0-7
    	lcd_write(addr,0);		
    }
    
    else 							//Address is on right chip
    {
    	en = 0;								//Enable: Start low
    	nop();								//Pause to take effect
    	cs1=1; cs2=0;						//Configure right chip
    
    	addr = 0b01000000 + (h_addr-64);	//Horizontal address (convert to 0-63)
    	lcd_write(addr,0);		
    
    	addr = 0b10111000 + v_addr;			//Vertical address
    	lcd_write(addr,0);		
    }
    }
    
    //------------------------------------------------------------------------------
    
    void lcd_font (u8 library, u8 offset)	//Function to select and display a font
    							//Selects left and right chip when h_addr is 0 and 64
    							//'library' selects which font array/collection to use
    							//'position' is sequence in which characters appear (eg: 'c' is 3rd)
    							//'offset' becomes the variable identifier (starting at '0')
    {
    u8	i;
    u8	width;
    u8	display;
    
    if(library==5) width=6;
    else width=1;				//Library 4
    
    offset *= width;			//There are 6 variables for each regular character, 1 for graphs
    							// eg: 1st variable for 1st character is at offset 0
    							//	   1st variable for 2nd character is at offset 6
    
    for(i=0; i<width; i++)		//6 writes needed per regular character, 1 for graphs & images
    {
    	if(h_addr==0)			//Enable left chip when starting to fill row
    	{
    		lcd_coord();		//Sets new address
    	}
    	else if(h_addr==64)		//Change to right chip for addresses 64-127
    	{
    		lcd_coord();		//Sets new address
    	}
    
    	if(library==4)	display = graph [offset+i];
    	else if(library==5)	display = graph1 [offset+i];
    
    	lcd_write( display, 1);		//Send chosen character to LCD
    	h_addr++;					//Increment horizontal / chip select counter
    }
    }	
    
    //------------------------------------------------------------------------------
    
    void lcd_write (u8 send, u8 mode)	//Function to send an instruction or data to the LCD
    								//'send' is the byte to be sent to LCD
    								//'mode' is 0=Instruction and 1=Data
    								//Addressing (including chip selection) is done elsewhere
    								//  (needs to be called before this function)
    {
    data = 0;					//Initialise port
    trisc = 1;					//PortC not outputting data (made an Input)
    en = 0;						//Enable: Start low
    nop();						//Pause to take effect
    
    rw = 0;						//RW: 0=Write
    if(mode==0) rs=0;			//RS: 0=Instruction
    else rs=1;					//RS: 1=Data
    nop();						//140ns delay before making Enable high (nop = 500ns @ 8Mhz)
    
    en = 1;						//Enable: High to execute
    nop();						//450ns delay before making Enable low
    trisc = 0;					//Port C: 0=Output to make data available
    data = send;				//Set the data (instruction or screen character) to be sent
    nop();
    
    en = 0;						//Enable: Low to end the write activity
    nop();
    rw = 1;						//Disable writing
    data = 0;					//Initialise port (in case port is read to check status)
    trisc = 1;					//PortC no longer an output
    }
    
    //-----------------------------------------------------------------------------
    
    void lcd_refresh ()			//Function to clear screen and 'fix' stuff after interrupts
    {
    u8	b;
    u8	i;
    
    s_addr = 0b11000000;		//Set scrolling to top (off)
    lcd_write(s_addr,0);		
    
    for(b=0; b<8; b++)				//Loop 8 times for all rows/'pages' ('X')
    {
    	h_addr = 0;
    	v_addr = b;
    
    	for(i=0; i<128; i++)		//Write accross whole screen
    	{
    		lcd_font(5,17);			//Space
    	}
    }
    }
    
    //-----------------------------------------------------------------------------
    
    void measure_cells (i16 iter)	//Function to measure cell voltages
    							//'iter' is number of times to perform measurements
    							// (more improves accuracy)
    							//iter must be 1, 2, 4, 8, 16, 32, 64, 128 or 256
    							//adc_result array gets cummulative measurements
    {	
    i16	i;
    
    //Measure cells
    for(i=0; i<pack_size; i++)	//Initialise array for cells needed
    {
    	adc_result[i] = 0;		//Initialise variable
    }
    
    for(i=0; i<iter; i++)		//Measure 'iter' times to smooth results
    {
    	adc(pack_size);			//10 measurements per iteration less highest and lowest = sum of 8
    }
    }
    
    //-----------------------------------------------------------------------------
    
    void adc (u8 cells)		//Function to trigger AD conversions
    					//'cells' are number of cells being measured
    					//Note: '2Tad' automatic acquisition delay has been configured
    					//Function keeps adding conversion results to adc_result array
    {
    u8	i;
    u8	k;
    u8	channel = 0;
    i16	highest[7] = 0;
    i16	lowest[7]  = 0;
    
    for(k=0; k<10; k++)			//Measure each cell 10 times (improves accuracy)
    {
    for(i=0; i<cells; i++)			//Run ADC for number of cells being measured (AN0 to AN9)
    {
    //Select channel
    	channel = i;				//Select cell number for next measurement
    								//eg: For 5th cell (AN4) i=4, 6th cell (AN8) i=5
    
    	if(i==5) channel+=3;		//AN5-AN7 don't exist on this chip so jump to AN8 after AN4
    
    	adcon0 = (channel*4) +1;	//Configures each channel (channel*4) and enables AD module (+1)
    								//eg: 5th cell: i=4, channel=4, 	4*4+1=17 ie: 0b010001=AN4
    								//eg: 6th cell: i=5, channel=5+3=8, 8*4+1=33 ie: 0b100001=AN8
    
    //Run ADC
    	pir1.6 = 0;					//ADIF: Clear the ADC Complete flag
    	adcon0.1 = 1;				//GO: Start ADC acquisition
    	while(adcon0.1==1);			//Wait for conversion to complete (becomes 0)
    
    //Merge results
    	MAKESHORT (result, adresl, adresh);	//Merges high and low registers
    	adc_result[i] += result;			//Sum each cell's results
    
    //Determine highest measurement
    	if (k==0) highest[i] = result;
    	else
    	{
    		if(result>highest[i]) highest[i]=result;
    	}
    
    //Determine lowest measurement
    	if (k==0) lowest[i] = result;
    	else
    	{
    		if(result<lowest[i]) lowest[i]=result;
    	}
    }
    }
    
    //Deduct highest and lowest measurements to exclude annomalies
    for(i=0; i<cells; i++)			//Run ADC for number of cells being measured (AN0 to AN9)
    {
    	adc_result[i] -= highest[i];	//Reduces 10 measurements to 9
    	adc_result[i] -= lowest[i];		//9 becomes 8
    }
    }
    
    //-----------------------------------------------------------------------------
    
    void volts_pack (i16 iter)		//Function to convert ADC values to cell voltages
    							//'iter' is number of times each has been measured
    							//Needs to be same as measure_cells()
    {
    u8	i;
    
    for(i=0; i<pack_size; i++)
    {
    	convert = adc_result[i];	//Select cell value to be converted
    	volts_calc ( (i+1), iter);	//Convert ADC value to volts
    								//'i+1' is cell number (1 is cell 1)
    								//'convert' is cell ADC value
    								//'iter' is # iterations the value comprises
    								// (how many times the cell was measured)
    
    	adc_result[i] = convert;	//Save converted value
    }
    
    //Determine single cell values (cell voltages are 'cumulative' (eg: cell 2 is 1+2))
    	if(adc_result[6]>adc_result[5]) adc_result[6] -= adc_result[5];	//Cell 7
    	if(adc_result[5]>adc_result[4]) adc_result[5] -= adc_result[4];	//Cell 6
    	if(adc_result[4]>adc_result[3]) adc_result[4] -= adc_result[3];	//Cell 5
    	if(adc_result[3]>adc_result[2]) adc_result[3] -= adc_result[2];	//Cell 4
    	if(adc_result[2]>adc_result[1]) adc_result[2] -= adc_result[1];	//Cell 3
    	if(adc_result[1]>adc_result[0]) adc_result[1] -= adc_result[0];	//Cell 2
    }
    
    //-----------------------------------------------------------------------------
    
    void volts_calc (u8 cell, i16 iter)//Function to convert ADC values to volts
    								//'cell' is cell number being converted (1-7)
    								//'iter' indicates how many times cells were measured
    								//Requires 'convert' to be populated elsewhere
    {
    convert *= (256/iter);	//Scale up to 2048 times bigger than single measurement
    						//adc(pack) above measures 10 times, discards 2 = 8
    						//Increase by a factor of 256 to get to 2048 (2048/8=256)
    						//2048 is chosen via spreadsheet to increase accuracy
    						//If iter=1 values will be x256
    						//If iter=16 values will be x16
    						//If iter=256 values will be x1
    
    if(cell==1)					//Adjust 1st cell (most have different resistor dividor ratio)
    {
    	convert += 6250;		//Compensate for PIC rounding (always down)
    	convert /= 6250;		//Scale down - per spreadsheet
    }
    else if(cell==2)				//2nd cell (different resistor ratio)
    {
    	convert += 6270;
    	convert /= 6270;
    }
    else if(cell==3)				//3th cell
    {
    	convert += 6270;
    	convert /= 6270;
    }
    else if(cell==4)				//4th cell
    {
    	convert += 4623;
    	convert /= 4623;
    }
    else if(cell==5)				//5th cell
    {
    	convert += 3818;
    	convert /= 3818;
    }
    else if(cell==6)				//6th cell
    {
    	convert += 3123;
    	convert /= 3123;
    }
    else							//7th cell
    {
    	convert += 2770;
    	convert /= 2770;
    }
    }
    
    //##############################################################################
    //Program eratic when this is here; works in lcd_deisplay()
    
    void log_highlow ()		//Function to determine highest and lowest logged voltages (mode 2)
    {
    u8	i;
    
    //Determine highest values
    for(i=0; i<96; i++)		//Finds highest out of 96 measurements for each cell
    {
    	if(i==0)
    	{
    		log_high[0]=log1[i];	//Start with first value
    		log_high[1]=log2[i];
    		log_high[2]=log3[i];
    		log_high[3]=log4[i];
    		log_high[4]=log5[i];
    	}
    	else
    	{
    		if(log1[i]>log_high[0]) log_high[0]=log1[i];
    		if(log2[i]>log_high[1]) log_high[1]=log2[i];
    		if(log3[i]>log_high[2]) log_high[2]=log3[i];
    		if(log4[i]>log_high[3]) log_high[3]=log4[i];
    		if(log5[i]>log_high[4]) log_high[4]=log5[i];
    	}
    }
    for(i=0; i<pack_size; i++)		//Finds highest of all cells measured
    {
    	if(i==0) log_highest=log_high[i];
    	else
    	{
    		if(log_high[i]>log_highest) log_highest=log_high[i];
    	}
    }
    
    //Determine lowest values
    for(i=0; i<96; i++)
    {
    	if(i==0)
    	{
    		log_low[0]=log1[i];	//Start with first value
    		log_low[1]=log2[i];
    		log_low[2]=log3[i];
    		log_low[3]=log4[i];
    		log_low[4]=log5[i];
    	}
    	else
    	{
    		if(log1[i]<log_low[0]) log_low[i]=log1[0];
    		if(log2[i]<log_low[1]) log_low[i]=log2[1];
    		if(log3[i]<log_low[2]) log_low[i]=log3[2];
    		if(log4[i]<log_low[3]) log_low[i]=log4[3];
    		if(log5[i]<log_low[4]) log_low[i]=log5[4];
    	}
    }
    for(i=0; i<pack_size; i++)		//Finds lowest of all cells measured
    {
    	if(i==0) log_lowest=log_low[i];
    	else
    	{
    		if(log_low[i]<log_lowest) log_lowest=log_low[i];
    	}
    }
    }
    
    //##############################################################################
    
    void display_graph ()	//Function to display logged data in graph (mode2)
    							//'cells' indicates all (0) or individual cells (1-5)
    {
    u8	d;
    u8	i;
    u8	k;
    
    i16	base;				//Value for lowest pixel in row (eg: 440 to 447 in top row)
    
    i16	disp;				//Converts integers to decimals for displaying data
    u8	line;				//Determines markers on vertical axis
    u8	buff[4];
    bit	ten;
    bit	hun;
    u8	offset;
    
    //##############################################################################
    //Special test section - When this code is here it works
    /*
    //Normally with global variables
    i16	log1[97];			//Stores measurements for cell 1 etc...
    i16	log2[97];
    i16	log3[97];
    i16	log4[97];
    i16	log5[97];
    
    //Normally in main()
    for(i=0; i<96; i++)
    {
    	log1[i] = (i16)adc_result[0];	//Store Cell 1's ADC values
    	log2[i] = (i16)adc_result[1];	//Cell 2 etc...
    	log3[i] = (i16)adc_result[2];
    	log4[i] = (i16)adc_result[3];
    	log5[i] = (i16)adc_result[4];
    }
    
    //Normally a separate function void log_highlow()
    //Determine highest values
    	for(i=0; i<96; i++)		//Finds highest out of 96 measurements for each cell
    	{
    		if(i==0)
    		{
    			log_high[0]=log1[i];	//Start with first value
    			log_high[1]=log2[i];
    			log_high[2]=log3[i];
    			log_high[3]=log4[i];
    			log_high[4]=log5[i];
    		}
    		else
    		{
    			if(log1[i]>log_high[0]) log_high[0]=log1[i];
    			if(log2[i]>log_high[1]) log_high[1]=log2[i];
    			if(log3[i]>log_high[2]) log_high[2]=log3[i];
    			if(log4[i]>log_high[3]) log_high[3]=log4[i];
    			if(log5[i]>log_high[4]) log_high[4]=log5[i];
    		}
    	}
    	for(i=0; i<pack_log; i++)		//Finds highest of all cells measured
    	{
    		if(i==0) log_highest=log_high[i];
    		else
    		{
    			if(log_high[i]>log_highest) log_highest=log_high[i];
    		}
    	}
    
    //Determine lowest values
    	for(i=0; i<96; i++)
    	{
    		if(i==0)
    		{
    			log_low[0]=log1[i];	//Start with first value
    			log_low[1]=log2[i];
    			log_low[2]=log3[i];
    			log_low[3]=log4[i];
    			log_low[4]=log5[i];
    		}
    		else
    		{
    			if(log1[i]<log_low[0]) log_low[i]=log1[0];
    			if(log2[i]<log_low[1]) log_low[i]=log2[1];
    			if(log3[i]<log_low[2]) log_low[i]=log3[2];
    			if(log4[i]<log_low[3]) log_low[i]=log4[3];
    			if(log5[i]<log_low[4]) log_low[i]=log5[4];
    		}
    	}
    	for(i=0; i<pack_log; i++)		//Finds lowest of all cells measured
    	{
    		if(i==0) log_lowest=log_low[i];
    		else
    		{
    			if(log_low[i]<log_lowest) log_lowest=log_low[i];
    		}
    	}
    */
    //End of special test section
    //##############################################################################
    
    
    if(log_highest>56) base=log_highest-7;	//Highest point at top of screen
    else base=49;							//Bottom of 7th row starts at 0.01v
    
    for(k=0; k<7; k++)			//Rows ('pages') in graph (each 8 dots high)
    {
    h_addr = 0;			//Initialise horizontal counter (toggles chip select)
    v_addr = k;			//Sets vertical counter
    
    base  -= k*8;		//Adjusts values relative to top of graph (eg: 440 if k=0, 432 if k=1)
    
    
    //High/low info in left margin
    if(cell_num>0)					//Displays individual cells, 1 at a time
    {
    	if(k==0)						//High value for cell at top
    	{
    		disp=log_high[(cell_num-1)];	//eg: Cell 3 is array variable 2
    		uitoa_dec (buff, disp, 3);
    
    		buff[0] -= 0x30;				//Convert ASCII to single character (-0x30)
    		lcd_font(5,buff[0]);			//Display value only if 100 or more
    
    		lcd_font(5,12);					//'.'
    
    		buff[1] -= 0x30;
    		lcd_font(5,buff[1]);			//Tenths
    
    		buff[2] -= 0x30;
    		lcd_font(5,buff[2]);			//Hundredths
    	}
    	else if(k==1)					//Lowest value measured on 2nd row
    	{
    		disp= log_low[(cell_num-1)];
    		uitoa_dec (buff, disp, 3);
    
    		buff[0] -= 0x30;				//Convert ASCII to single character (-0x30)
    		lcd_font(5,buff[0]);			//Display value only if 100 or more
    
    		lcd_font(5,12);					//'.'
    
    		buff[1] -= 0x30;
    		lcd_font(5,buff[1]);			//Tenths
    
    		buff[2] -= 0x30;
    		lcd_font(5,buff[2]);			//Hundredths
    	}
    	else if(k==2)						//Cell number on 3rd row
    	{
    		lcd_font(5,17);						//Normal spaces (x 6px)
    		lcd_font(5,11);						//'#'
    		lcd_font(5,(cell_num));				//Cell number
    		lcd_font(5,17);						//Normal spaces (x 6px)
    	}
    	else								//Spaces on other rows
    	{
    		for(i=0; i<4; i++) lcd_font(5,17);	//Normal spaces (x 6px)
    	}
    }
    
    if(cell_num==0)					//Displays all cells
    {
    	if(k==0)						//Highest of all cells at top
    	{
    		disp=log_highest;				//Highest in pack
    		uitoa_dec (buff, disp, 3);
    
    		buff[0] -= 0x30;				//Convert ASCII to single character (-0x30)
    		lcd_font(5,buff[0]);			//Display value only if 100 or more
    
    		lcd_font(5,12);					//'.'
    
    		buff[1] -= 0x30;
    		lcd_font(5,buff[1]);			//Tenths
    
    		buff[2] -= 0x30;
    		lcd_font(5,buff[2]);			//Hundredths
    	}
    	else if(k==1)					//Lowest of all cells on 2nd row
    	{
    		disp=log_lowest;				//Lowest in pack
    		uitoa_dec (buff, disp, 3);
    
    		buff[0] -= 0x30;				//Convert ASCII to single character (-0x30)
    		lcd_font(5,buff[0]);			//Display value only if 100 or more
    
    		lcd_font(5,12);					//'.'
    
    		buff[1] -= 0x30;
    		lcd_font(5,buff[1]);			//Tenths
    
    		buff[2] -= 0x30;
    		lcd_font(5,buff[2]);			//Hundredths
    	}
    	else if(k==2)					//Cell number on 3rd row
    	{
    		lcd_font(5,13);					//A
    		lcd_font(5,14);					//l
    		lcd_font(5,14);					//l
    		lcd_font(5,pack_log);			//Number of cells measured
    	}
    	else							//Spaces on other rows
    	{
    		for(i=0; i<4; i++) lcd_font(5,17);	//Normal spaces (x 6px)
    	}
    }
    
    
    //Vertical axis (scale markings every 1.00 and 0.10v)
    lcd_font(4,8);			//1px spaces (padding)
    
    ten = 0;				//Initialise 10 step counter (every 0.10v)
    hun = 0;				//100 step counter (every 1.00v)
    
    for(i=0; i<8; i++)		//Test all 8 vertical bits to see if multiple of 10 or 100
    {
    	if( (base+i)/10 > (base-1+i)/10 )		//Test for multiples of 0.10v ('10' = 0.10v)
    					//PICs always rown down
    					//So, this test will only increment when multiples of 10 are reached
    					//base is the lowest value in the current row (eg: 440)
    					//base-1 is the value immediately neneath it (eg: 439)
    					//The test will be true once only when changing to a higher multiple of 10
    	{
    		ten = 1;		//0.10v flag
    		offset = i;		//Vertical location
    	}
    
    	if( (base+i)/100 > (base-1+i)/100 )	//Test for multiples of 1v ('100' = 1.00v)
    	{
    		hun = 1;		//1v flag
    		ten = 0;		//0.10v flag
    		offset = i;		//Vertical location
    	}
    }
    
    if(hun==1)
    {
    	for(d=0; d<5; d++) lcd_font(4,offset);	//Create 5 dots to indicate a multiple of 100
    }
    else if(ten==1)
    {
    	for(d=0; d<3; d++) lcd_font(4,8);		//Create 3 blank spaces for smaller indicator
    	for(d=0; d<2; d++) lcd_font(4,offset);	//Create 2 dots to indicate a multiple of 10
    }
    else
    {
    	for(d=0; d<5; d++) lcd_font(4,8);//Create 5 blank spaces if no multiples of 10 or 100
    }
    
    lcd_font(4,9);			//|Vertical line
    lcd_font(4,8);			//1px space (padding)
    
    
    //Graph lines
    for(i=0; i<96; i++)		//Scroll across screen pixel by pixel (96 logged measurements)
    {
    	if(cell_num==1)				//Cell 1
    	{
    		if( log1[i]>(base-1) && log1[i]<(base+8) )//eg: between 440 and 447 (in top row's range)
    		{
    			line = (u8)(log1[i]-base);	//Converts to 7-0 (eg: 440 becomes 0, 447 becomes 7)
    			lcd_font(4,line);			//Send this offset location to LCD
    		}
    		else 	lcd_font(4,8);
    	}
    	if(cell_num==2)				//Cell 2
    	{
    		if( log2[i]>(base-1) && log2[i]<(base+8) )
    		{
    			line = (u8)(log2[i]-base);
    			lcd_font(4,line);
    		}
    		else 	lcd_font(4,8);
    	}
    	if(cell_num==3)				//Cell 3
    	{
    		if( log3[i]>(base-1) && log3[i]<(base+8) )
    		{
    			line = (u8)(log3[i]-base);
    			lcd_font(4,line);
    		}
    		else 	lcd_font(4,8);
    	}
    	if(cell_num==4)				//Cell 4
    	{
    		if( log4[i]>(base-1) && log4[i]<(base+8) )
    		{
    			line = (u8)(log4[i]-base);
    			lcd_font(4,line);
    		}
    		else 	lcd_font(4,8);
    	}
    	if(cell_num==5)				//Cell 5
    	{
    		if( log5[i]>(base-1) && log5[i]<(base+8) )
    		{
    			line = (u8)(log5[i]-base);
    			lcd_font(4,line);
    		}
    		else 	lcd_font(4,8);
    	}
    }			//end graph lines
    
    
    }		//end 'k' counter (7 rows)
    }		//end function
    
    
    //===========================================================================
    
    void main()					//main program
    {
    bit	b;
    u8	d;
    i16 i;
    bit	capture;
    
    //Initialise all ports, etc
    porta=0; portb=0; portc=0;		//Start low
    lata=0; latb=0; latc=0;			//Start low
    
    //Set oscillator frequency
    osccon.6 = 1;
    osccon.5 = 1;
    osccon.4 = 1;					//8mhz
    //osccon.4 = 0;					//4mhz
    
    //Main port settings (1=Input 0=Output)
    						//Pin1	RE3			ICSP (tris.3 does not exist)
    trisa.0 = 1;			//2		RA0	AN0		Cell1
    trisa.1 = 1;			//3		RA1	AN1		Cell2
    trisa.2 = 1;			//4		RA2	AN2		Cell3
    trisa.3 = 1;			//5		RA3	AN3		Cell4
    trisa.4 = 0;			//6		RA4			#spare#
    trisa.5 = 1;			//7		RA5	AN4		Cell5
    trisa.7 = 0;			//9		RA7			RW
    trisa.6 = 0;			//10	RA6			DI/RS
    
    trisc = 0;				//11-18	RC0-7		D0-7 (LCD data)
    
    trisb.0 = 1;			//21	RB0	AN12	menu push-button
    trisb.1 = 1;			//22	RB1	AN10	select push-button
    trisb.2 = 1;			//23	RB2	AN8		Cell6
    trisb.3 = 1;			//24	RB3	AN9		Cell7
    trisb.4 = 0;			//25	RB4	AN11	Reset
    trisb.5 = 0;			//26	RB5			Enable
    trisb.6 = 0;			//27	RB6			ICSP / CS1
    trisb.7 = 0;			//28	RB7			ICSP / CS2
    
    
    //ADC settings
    adcon1.5 = 0;			//VCFG1: Vref low = Vss
    adcon1.4 = 0;			//VCFG0: Vref high = Vdd
    
    adcon1.3 = 0;			//PCFG: AN0-9 analogue, AN10-12 digital
    adcon1.2 = 1;			//PCFG: part of above
    adcon1.1 = 0;			//PCFG: part of above
    adcon1.0 = 1;			//PCFG: part of above
    
    adcon2.7 = 1;			//ADFM	Right justify results
    
    adcon2.5 = 0;			//ACQT: Acquisition time (2 Tad - see spreadsheet)
    adcon2.4 = 0;			//ACQT: part of above
    adcon2.3 = 1;			//ACQT: part of above
    
    adcon2.2 = 0;			//ADCS: AD conversion clock (Fosc/8 - see spreadsheet)
    adcon2.1 = 0;			//ADCS: part of above
    adcon2.0 = 1;			//ADCS: part of above
    
    //Interrupts
    rcon.7 = 0;				//IPEN: Interrupt priorities disabled
    intcon.7 = 1;			//GIE: Enables interrupts globally
    
    intcon.4 = 1;			//INT0IE: RB0 interrupt enabled ('menu')
    intcon3.3 = 1;			//INT1IE: RB1 interrupt enabled ('select')
    intcon2.6 = 0;			//INTEDG0: RB0 interrupt on falling edge (weak pullups hold high)
    intcon2.5 = 0;			//INTEDG1: RB1 interrupt on falling edge
    
    //Weak pullups
    intcon2.7 = 0;			//RBPU: Weak pullups enabled for PortB (all digital input pins)
    
    //Pause
    delay_ms(250);			//Delay to prevent programmer from interferring and allows LCD to start
    
    //Static EEPROM data logging settings
    eecon1.6 = 0;				//CFGS: Access data not config
    eecon1.3 = 0;				//WRERR: clear on startup in case previously set
    
    //------------------------------------------------------------------------------
    
    //Initialise LCD etc
    b=1;
    for(i=0; i<2; i++)				//Switch both halves of screen
    {
    	cs1=b; b++;					//Toggles chip selection bits (0=selected; 1=deselected)
    	cs2=b;
    	lcd_write(0b00111111,0);	//Switch display on
    
    	s_addr = 0b11000000;		//Set scrolling to top (off)
    	lcd_write(s_addr,0);		
    }	
    
    lcd_refresh();			//Clear screen and set scrolling to top
    
    mode = 2;				//Start mode
    mode_min = 0;			//Default smallest menu choice (wraps backwards to largest)
    mode_max = 2;			//Default largest menu choice (wraps forwards to smallest)
    
    sel = 3;				//Default selection (usually pack size)
    sel_min = 1;			//Default minimum allowed in each mode
    sel_max = 7;			//Default maximum allowed in each mode
    
    pack_size = 3;			//Default pack size for mode 1
    pack_log = 3;			//Default maximum pack size for mode 2
    cell_num = 3;			//Default cell number
    capture = 0;			//Mode 2 capture not performed yet
    
    for(d=0; d<7; d++)		//Initialise Mode 2 array
    {
    	log_high[d] = 0;
    	log_low[d] = 0;
    }
    
    log_highest = 448;		//Set default graph scaling
    log_lowest = 0;
    
    //===========================================================================
    
    while(1)
    {
    
    	for(i=0; i<96; i++)		//96 iterations of cell measurements
    
    	{
    		measure_cells(8);	//Measure cells 8 times each
    		volts_pack(8);		//Determine voltages
    
    //##############################################################################
    //This section copied to lcd_display() to make it work
    
    		log1[i] = (i16)adc_result[0];	//Store Cell 1's ADC values
    		log2[i] = (i16)adc_result[1];	//Cell 2 etc...
    		log3[i] = (i16)adc_result[2];
    		log4[i] = (i16)adc_result[3];
    		log5[i] = (i16)adc_result[4];
    
    	}
    	log_highlow();			//Determine highest and lowest logged voltages using pack_size
    
    //##############################################################################
    
    	display_graph();			//Display on LCD
    
    	while(1);
    
    
    }				//end while
    }					//end main


  10. 1. The easiest is to store data in normal RAM using variables or an array.

    2. However, I suspect you are referring to program memory (ROM) which can be written to when programming with the BoostC 'rom' command and read at any time.

    3. If you want your PIC program to update this data on the fly you need to have a device which supports 'self-write' ('Enhanced Flash' versions in the 16F series or available in most or all? 18F's). Harder than 1 or 2.

    4. External memory will be more work than 3.

    David.


  11. Hi, The following code is intended to populate EEPROM to confirm that the PIC is working.

     

    When I use delay_ms(1) at 8MHz it populates the first three bytes of EEPROM as intended.

    When I use delay_s(1) at 8MHz EEPROM does not get populated.

    When I change the clock to 4MHz delay_s(1) EEPROM gets populated.

     

    So there appears to be a problem with delay_s(1) at 8MHz. I'm using an 18F2523 with IDE 6.81 on XP.

    Thanks, David.

    #include <system.h>
    
    //Core configuration (rest left at default):
    #pragma DATA 0x300001, 0b1000		//Config1H: Internal oscillator with IO on RA6 and 7
    #pragma DATA 0x300006, 0b10000001	//Config4L: Debug, Extended instructions and low voltage programming all off
    
    #pragma CLOCK_FREQ 8000000			//8MHz
    
    void eeprom_write()				//Function to write to EEPROM flash memory
    {
    eecon1.2 = 1;				//WREN: enable writing to memory
    intcon.7 = 0;				//Disable all interrupts while writing to memory
    pir2.4 = 0;					//EEIF: Clear this bit which gets set after each write
    
    eecon2 = 0x55;				//Required before writing to memory
    eecon2 = 0xAA;				//Required before writing to memory
    eecon1.1 = 1;				//WR: Writes data eedata to address eeadr
    
    while(eecon1.1==1);			//Wait for write to complete (becomes 0 when complete)
    eecon1.2 = 0;				//WREN: Disable writing to memory (while not in use)
    }
    
    void main()
    {
    char i;
    
    delay_s(1);
    
    eecon1.7 = 0;				//EEPGD: Access data memory
    eecon1.6 = 0;				//CFGS: Access data not config
    eecon1.3 = 0;				//WRERR: clear on startup in case previously set
    
    for(i=0; i<3; i++)			//Test to ensure PIC is working
    {
    	eeadr = i;
    	eedata = i+1;
    	eeprom_write();
    }
    
    while(1);
    
    }


  12. I can't guarantee that the following code will work but I've tried to extract the relevant parts from a project of mine:

    David.

    #include <system.h>
    
    #pragma DATA _CONFIG, _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO
    #pragma CLOCK_FREQ 4000000
    
    #define rs		portb.4		//Register Select
    #define en		portb.5		//Enable
    #define data	portc		//Characters or instructions for sending to LCD
    						//Assume RW is permamnently low
    
    void main(void)
    {
    //Initialise all ports
    porta=0; portb=0; portc=0;
    
    //Main port settings (1=Input 0=Output)
    trisa = 0;			//All pins Output
    
    trisb = 0;			//All pins Output except...
    trisb.4 = 1;		//RB4
    trisb.5 = 1;		//RB4
    
    trisc = 0;			//All pins Output
    
    //Initialise LCD
    char	i;			//Decalre variable for counter
    delay_ms(250);		//Wait for LCD to start
    
    //'Set Function'
    for(i=0; i<3; i++)	//Send instruction 3 times to stabilise display
    {
    	data=0b.00111000;	//8bit, 2 lines, 5x7
    	rs=0;				//Set RS low for instructions
    	nop();				//Brief delay
    	en=1;				//Set Enable high before writing
    	nop();				//Brief delay
    	en=0;				//Execute by pulling low
    	delay_ms(1);		//Wait to complete
    }
    
    //'Display Clear' and return cursor to home position
    	data=0b00000001;	//Clear display
    	rs=0; nop(); en=1; nop();
    	en=0; delay_ms(1);
    
    //'Set Entry Mode' sets cursor auto-increment direction
    	data=0b00000110;	//Increment cursor (right) after writing; don't shift display
    	rs=0; nop(); en=1; nop();
    	en=0; delay_ms(1);
    
    //'Cursor/Display Shift' sets cursor move direction
    	data=0b00010100;	//Increment address and moves cursor right
    	rs=0; nop(); en=1; nop();
    	en=0; delay_ms(1);
    
    //'Display ON' enables display/cursor
    	data=0b00001111;	//Display on, cursor on, blinking on
    	rs=0; nop(); en=1; nop();
    	en=0; delay_ms(1);
    
    
    //Send data	
    data=0x31;				//Send ASCII '1'
    rs=1; nop(); en=1; nop();
    en=0; delay_ms(1);
    
    data=0x32;				//Send ASCII '2'
    rs=1; nop(); en=1; nop(); 
    en=0; delay_ms(1);
    
    
    while(1);
    
    }			//end main

×
×
  • Create New...