I’ve been a little busy on the workbench lately. I’ve been working late at the-day-job so I’ve been neglecting my workbench notebook and my blog for most of this week. I’ve got a ton of “fun” stuff planned for this weekend; no way I’ll get it all done.
I won’t make you read through the whole post if I pulled you in with mouse hacking 😉
I am a poor gamer.. give me a cheat code and I’ll use it. I have no shame in gaming. Adam Fabio recently got me slightly addicted to ClickingBad … I refuse to link it, don’t search for it.. it’s a god-awful time suck. I clicked a freakn’ mouse for 90 minutes straight… Well screw that. I pulled out one of those el-cheapo USB mice you get with a refurb computer… the $5 throw-away kind. I popped it open and as luck would have it little microswitchs on a single sided PCB. Well 2-1/2 minutes later I had soldered wires to the switch contacts, dumped them on the normal open contacts of a small relay, hooked it up the relay coil to my MOSFET driver (yes, way overkill, it was laying there already), and threw it under a PIC. I used a rate of 70 ms off 40 ms on.. I probably could have sped that up but it was at that warp speed, I was happy. Did it take away from the game? Nah, I had that much more to buy! I was shocked the relay held out for a few days of being hammered (“Batches hand-cooked: 1.01Q” , that’s not a quadrillion clicks, but it was a lot regardless). I pulled my cheat-clicker off after a while because the super-fast click of the relay was getting pretty damn annoying. I had little bug in the system: a little phantom drift issue with the el-cheapo mouse so turned down pointer sensitivity to as slow as possible; That allowed for a couple hour stretch of non-stop cheating.
Continuing on with actual electronics projects: I have five active projects I’m working on, a few I’ve recently benched waiting on a big purchase, trying to get other stuff out of the way or for other reasons.
1. Video Synth … Lawrence has inspired me to help him build a Video Synth. I’ve gotten a fair amount of reading done. Looks like I’m going to need a spectrum analyzer for some filters I want to build (awww darn! heh). I’ve gotten some boards finished which I needed for other projects but just happened to work for this one as well.
… version 2.0 of these boards in at the fab. I’ll probably sell some of these for people needed a quick sweep generator for their VCOs, etc.
2. Workshop Time Standard — Just started this because I got most of the parts in. This will be powered by my MikroElectronika PIC clicker and GPS2 click…. Stay Tuned.
3. WWVB for non-US persons… Edward contacted me about using my WWVB project but to actually broadcast the correct time. Well, fair enough. This has gotten me to buy all the stuff I think I need to create a PIC NTP client, GPS NMEA input .. and then the easy part. Broadcast it on 60KHz… I’ll have some kind of notice you should do this in a lead box under the ocean. I certainly wouldn’t sell this to someone within the US. I don’t think the FCC has any rule that allows a person to broadcast any tiny amount of power on 60KHz, certainly not intentionally. I didn’t find anything I thought I’d be safe under Part 15. I’d love to be proven wrong on this.. really.
4. My electric scooter. I just got a welder … now for some more material. Most of the electronics are done-enough until testing.
5. My ESR meter… waiting on parts of course.. come on Customs.. let me have my fun-stuff.
… all this work has left me bench a disaster zone.
Jayson Tautic had mentioned, on IRC the other day, a Fourth system with the ability to run on a PIC… that pretty cool (mad scientist stuff!). It prompted me to consider connectivity; I posted my progress on the recent Digi One SP project that came out of that on my last post.
It’s been noticed that Jayson sleeps far fewer hours than I do, this is further proof! At lightning speeds (maybe that’s why he sells a lightning sensor?) he has his Pi running ser2net which connects the internet to a terminal port and from there to the serial port of his PIC running FlashForth. Jayson has Forth running on an 18F14K22 on his 20pin dev board which can also be found on his tindie store. I have never reviewed/commented on someone else’s project but I thought this was extremely clever and demanded attention. He won’t admit it was much of course, he’s far to modest. What’s next? What does this open up for us 8-bit PIC developers? Well I tell you what.. I have some ideas you’ll see in the near future!
Today was a FR4-AIL day, again. Still no PCBs in the mail today; I suspect this will be a PITA because they never left the Oregon post office.
With that I wasn’t really in the mood for any “real” electronics today. Jayson Tautic mentioned he put Fourth on a PIC 18F14K22 which is pretty cool. It got me thinking, one thing and then another and on to connectivity which lead me digging into the old project bins.
I’m sure it’s been done over and over but it hasn’t been done by me; I’ll see if I can put a PIC online. Maybe a simple text game?
Out of the projects bin came a Rev A11 XPort… well an hour later it went right back into the box. I think the old versions weren’t really friendly for what I was thinking.. next attempt was a Digi One SP. I bought one off eBay a while back; I’m way more familiar with these as I had installed a couple of them for a radio station for some telemetry.
The whole set up on the Digi One SP is pretty easy; logon by web browser, set up a static IP, etc, etc… the only tricky part was Serial Port set up. It would seem the Serial Port Profile setup should be to the “Modem In” profile but in fact to initiate a connection from ethernet you need to choose “Modem Out”. No problem..
So this is how I tested the setup:
I used RealTerm to connect to the serial port, it’s ANSI emulation but I used ASCII so I could the control characters. I connected my EdgePort (USB<–>RS232) through a null modem adapter to the DigiOne SP. On the ethernet side I used Putty; with a little poking I connected to the Digi One with “RAW” TCP to port 2001.
The connection tidbits are done, now I have to order a wireless bridge so I can get an ethernet port down in my bench (all wifi)… in the mean-time I also set up dyndns with my router because we don’t have a static IP address… TBC.
To be honest, I have never considered using the PIC 16F1509 digital to analog converter before. I was considering integrating a DAC internally or externally to a microcontroller for my brother’s synth project. I started on the microchip site and found a number of smaller PICs, 12F1501.. 16F1503, that had a 5bit DAC. The 16F753 has a 9bit and the 16F17* series has a 8bit DAC. I stuck with the old standby 16F1509 as I needed a serial port for MIDI and I had it sitting on an easy-to-use dev board. I ordered a 16F17* series PIC a while back because they have some interesting peripherals and I will probably build a board around it for the resolution.
Turns out the DAC is probably the easiest peripheral I’ve used on the PIC. It took me longer to wait for the PICKit to update from 18F configuration to 16F. BUT.. if you’re having issues.. here you go:
A simple voltage follower (or however you want to buffer the output) is needed on the DAC output. It’s not designed to drive anything.
Don’t expect screaming speeds out of this thing…it’s just not going to happen. I ran mine up to 1.3KHz, which is more than enough for what I’m trying to accomplish. If you put an A/D converter in you could use that to control your ramp speed and you’d have yourself a nice driver for your VCO input on test equipment with properly conditioned output.
The code:
/*
* File: main.c
* Author: Charles M Douvier
* Contact at: http://iradan.com
*
* Created on April 13, 2014, 1:14 PM
*
* Target Device:
* 16F1509 on Tautic 20 pin dev board
*
* Project: DAC ramp test
*
* Version:
* 1.0
*
*/
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
#endif
#include
#include
#include
#include
//config bits
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=OFF, MCLRE=ON, CP=OFF, BOREN=ON, CLKOUTEN=OFF, IESO=OFF, FCMEN=OFF
#pragma config WRT=OFF, STVREN=OFF, LVP=OFF
#define _XTAL_FREQ 4000000 //defined for delay
int x; //DAC counter
/*
*
*/
void init_io(void) {
TRISAbits.TRISA0 = 0; // output
TRISAbits.TRISA1 = 0; // output
TRISAbits.TRISA2 = 0; // DAC2
TRISAbits.TRISA3 = 0; // output
TRISAbits.TRISA4 = 0; // output
TRISAbits.TRISA5 = 0; // output
// TRISAbits.TRISA6 = 0; // output
// TRISAbits.TRISA7 = 0; // output
ANSELA = 0x00; // all port A pins are digital I/O
TRISBbits.TRISB4 = 0; // RB4 = nc
TRISBbits.TRISB5 = 1; // RB5 = nc
TRISBbits.TRISB6 = 0; // RB6 = nc
TRISBbits.TRISB7 = 0; // RB7 = nc
ANSELB = 0x00; // all port B pins are digital I/O
TRISCbits.TRISC0 = 0; // output
TRISCbits.TRISC1 = 0; // output
TRISCbits.TRISC2 = 0; // output
TRISCbits.TRISC3 = 0; // output
TRISCbits.TRISC4 = 0; // output
TRISCbits.TRISC5 = 0; // output
TRISCbits.TRISC6 = 1; // input
TRISCbits.TRISC7 = 1; // input
ANSELC = 0x00; // all port B pins are digital I/O
}
void init_dac(void)
{
DACCON0bits.DACPSS = 0; //VDD ref
DACCON0bits.DACOE2 = 1; //output 2 enable (RA2)
DACCON0bits.DACEN = 1; //enable DAC
}
int main(void) {
// set up oscillator control register, using internal OSC at 4MHz.
OSCCONbits.IRCF = 0x0d; //set OSCCON IRCF bits to select OSC frequency 4MHz
OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
OPTION_REGbits.nWPUEN = 0; // enable weak pullups (each pin must be enabled individually)
init_io();
init_dac();
x = 0;
while (1) {
for (x = 0; x < 31; ++x)
{ //DAC is 5 bit
DACCON1bits.DACR = x; //dump count into DAC value
__delay_us(25);
}
}
return (EXIT_SUCCESS);
}
Today I received the first of a couple batches of PCBs from OSH Park. This set is a simple MOSFET w/ driver. The MOSFET can be logic level driven and all my testing was done at 5VDC however the driver had a wide voltage range so running this at 9V or 12V should present no issues (16V max! VGS). I do have a few minor adjustments I want to add (silk screen additions and adjustments). I built this board as an electric scooter motor drive and I tested it with the motor I was interested in using and thankfully all testing worked out well including loading my power supply at max load for over an hour straight 🙂 This board can be used for an assortment of load control applications.
The build was easy enough, next board I think I’ll just skip the chipquik and stick to straight soldering iron… and I think I also “figured out” the trick to solder the heat sink without making too much of a mess.
I tested the load for 60 minutes at 66% duty cycle and 1.5KHz PWM with total load at 140watts (45Volts 3.1 Amps).. the heat sink temperature on the MOSFET raised from ambient (78 deg F) to 90.7 deg F (32.3 deg C) steady for an hour. The MOSFET is rated for 55V (max) at 30 amps but the board isn’t designed to handle that load. I used 50mil power traces which is roughly 3 amp handling according to the google machine; 5A if you don’t mind a 40 deg C rise (though there is a fan) so I’ll call this a 140W MOSFET board (47×3). I personally feel I could squeeze more current out of this in short bursts but I would need to do more testing.. and I can’t promise anything along those lines. The PWM signal was generated and directly fed from a PIC 18F16K22 microcontroller running @ 5V. You’re NOT going to be able to drive this at 3.3V.
I will likely stick a 75VDSS MOSFET in the next revision…
.. I’m considering selling these on Tindie. If you’re interested in getting on of these “BETA” boards at cost let me know before they’re gone.
Took a while to clear off the bench tonight. I got a little happy with the ORDER button last week through weekend. I’ve filled two more parts storage containers and luckily one of my new packages with another parts storage container from Amazon; I couldn’t find any locally, I hope they’re still making them.
The last thing I got to was this “Gauge Stepper Breakout” I got off The Rengineer (The Renaissance Engineer)’s Tindie store. Adam took this very nice stepper motor, put a gauge needle on it (which I believe he 3D printed, or at least it looks like it) and some nice diodes for voltage protection. What’s great about this board is you can drive it right from your microcontroller. I’m sure I don’t need to tell you how weird that is.. I worry about big LEDs.. but here this stepper was happy as a clam being powered by my PIC. I still might consider at least buffering this if I was to place it in a permanent circuit.
Adam’s provides links to some Arduino libraries but he was saved me a ton of time and just happened to have some PIC sample code! Not before I had about 75% of a ECCP program completed. (I’ll link some of that code if you’re looking for an example of Enhanced PWM output). Once I had Adam’s code I ported it to the TAUTIC 18F26K22 dev board because I already had one on the breadboard. That was mostly changes in the TMR0 (timer 0) code. The only thing of note is check out my IO comments for wiring. You have to cook up 5V/GND to this board then I drove RC3 –> A1 RC2 — A2, RC1 –> B1 and RC0 –> B2. When I had it flipped around the stepper moved in the opposite direction of how I wanted.
A little video of the code in action:
This code is a little sloppy but I just testing this out and it did the trick:
/*
* File: main.c
* Author: Charles M Douvier Contact at: http://iradan.com
* Core Driver Code by Adam F. of http://www.therengineer.com/
*
* Created on April 4th, 2014
*
* Target Device:
* TAUTIC PIC 18F26K22 Dev Board
*
* Project:
*
*
* Version:
* 1.0
*
*/
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
#endif
#include
#include
#include
#include
//config bits
#pragma config FOSC=INTIO67, WDTEN=OFF, PWRTEN=OFF, CP0=OFF, CP1=OFF, BOREN=ON
#pragma config STVREN=ON, LVP=OFF, HFOFST=OFF, IESO=OFF, FCMEN=OFF
//WRT=OFF, FOSC=INTOSC, MCLRE=ON
#define _XTAL_FREQ 4000000 //defined for delay
#define MIN_STEPS_LEFT 23
#define MAX_ACCEL_INDEX 6
#define MAX_STEP 945 /* motor can move 945 steps from stop to stop*/
int an8_value, an9_value; //value for a/d
char buf[10]; //buff for iota
long int fvar; //long for format math
long int tens; //left of decm
long int decm; //decimal places
int tempi; //to add leadign zeros..
int vtxdata; //volts int for TX
int itxdata;
unsigned short defaultAccelTable[][2] =
{
{ 1750, 3},
{ 1149, 3},
{ 926, 3},
{ 794, 3},
{ 709, 3},
{ 666, 4},
{ /*629*/450, 4},
};
unsigned int currentStep;
unsigned char currentState;
unsigned char stateMap[] = {0x09, 0x01, 0x07, 0x06, 0x0E, 0x08};
unsigned char serialBuffer[10];
unsigned char serialByteCount;
static const unsigned char stateCount = 6;
volatile unsigned int uart_data; // use 'volatile' qualifer as this is changed in ISR
/*
*
*/
void interrupt ISR() {
if (PIR1bits.RCIF) // see if interrupt caused by incoming data
{
uart_data = RCREG; // read the incoming data
PIR1bits.RCIF = 0; // clear interrupt flag
}
}
void init_io(void) {
TRISAbits.TRISA0 = 0; // output
TRISAbits.TRISA1 = 0; // output
TRISAbits.TRISA2 = 0; // output
TRISAbits.TRISA3 = 0; // output
TRISAbits.TRISA4 = 0; // output
TRISAbits.TRISA5 = 0; // output
TRISAbits.TRISA6 = 0; // output
TRISAbits.TRISA7 = 0; // output
ANSELA = 0x00; // all port A pins are digital I/O
LATAbits.LATA0 = 0;
PORTAbits.RA0 = 0;
TRISBbits.TRISB1 = 0; //P1C output
TRISBbits.TRISB2 = 0; // P1B output
TRISBbits.TRISB3 = 1; // AN9 speed control 0-5V
TRISBbits.TRISB4 = 0; // P1D output
TRISBbits.TRISB5 = 1; // RB5 = nc
TRISBbits.TRISB6 = 0; // RB6 = nc
TRISBbits.TRISB7 = 0; // RB7 = nc
ANSELB = 0b00001000; //RB3, AN9
TRISCbits.TRISC0 = 0; // output to B2 .. reversed to stoke the right direction
TRISCbits.TRISC1 = 0; // output to B1
TRISCbits.TRISC2 = 0; // output to A2
TRISCbits.TRISC3 = 0; // output to A1
TRISCbits.TRISC4 = 0; // output
TRISCbits.TRISC5 = 0; // output
TRISCbits.TRISC6 = 0; // output
TRISCbits.TRISC7 = 0; // output
ANSELC = 0x00; // all port B pins are digital I/O
}
void uart_xmit(unsigned int mydata_byte) {
while(!TXSTA1bits.TRMT); // make sure buffer full bit is high before transmitting
TXREG = mydata_byte; // transmit data
}
void serial_init(void)
{
//9600 8N1
// calculate values of SPBRGL and SPBRGH based on the desired baud rate
//
// For 8 bit Async mode with BRGH=0: Desired Baud rate = Fosc/64([SPBRGH:SPBRGL]+1)
// For 8 bit Async mode with BRGH=1: Desired Baud rate = Fosc/16([SPBRGH:SPBRGL]+1)
TXSTA1bits.BRGH=1; // select low speed Baud Rate (see baud rate calcs below)
TXSTA1bits.TX9=0; // select 8 data bits
TXSTA1bits.TXEN = 1; // enable transmit
RCSTA1bits.SPEN=1; // serial port is enabled
RCSTA1bits.RX9=0; // select 8 data bits
RCSTA1bits.CREN=1; // receive enabled
SPBRG1=25; // here is calculated value of SPBRGH and SPBRGL
SPBRGH1=0;
PIR1bits.RCIF=0; // make sure receive interrupt flag is clear
PIE1bits.RCIE=1; // enable UART Receive interrupt
INTCONbits.PEIE = 1; // Enable peripheral interrupt
INTCONbits.GIE = 1; // enable global interrupt
__delay_ms(50); // give time for voltage levels on board to settle
uart_xmit('R'); // transmit some data
}
// All this motor and timer code is from Adam with very minor changes to fit the processor
void t0Delay(unsigned int usec)
{
unsigned int t0ticks; //16 microsecond timer0 ticks
unsigned char t0Preload;
if(usec<16)
{
t0ticks=1;
}
else
{
t0ticks = usec/16;
}
t0Preload = 0xFF - t0ticks;
INTCONbits.TMR0IF=0; //clear the flag
TMR0 = t0Preload;
while(INTCONbits.TMR0IF==0)
{
;
}
}
void zeroMotor()
{
unsigned int i;
for (i=0; i < MAX_STEP; i++)
{
LATC=stateMap[currentState];
currentState = (currentState + 5) % stateCount;
t0Delay(1900); //2200 in datasheet
}
//now the motor is zeroed, reset our state variables.
currentStep = 0;
currentState = 0;
LATC=0; //turn off coils
}
void moveMotor(unsigned int targetStep)
{
unsigned int dir;
unsigned int curDelay;
unsigned char speedIndex=0;
unsigned char stepsAtThisSpeed=0;
unsigned int stepsLeft;
if(currentStep<targetStep) { dir = 1; stepsLeft = targetStep-currentStep; } else { dir = -1; stepsLeft = currentStep - targetStep; } while(stepsLeft>0)
{
if(stepsLeft<=MIN_STEPS_LEFT) { //decellerating if(stepsAtThisSpeed==0) { if(speedIndex>0)
speedIndex--;
curDelay=defaultAccelTable[speedIndex][0];
stepsAtThisSpeed=defaultAccelTable[speedIndex][1];
}
}
else
{
//accellerating or steady state
if(stepsAtThisSpeed==0)
{
if(speedIndex<MAX_ACCEL_INDEX) { speedIndex++; curDelay=defaultAccelTable[speedIndex][0]; stepsAtThisSpeed=defaultAccelTable[speedIndex][1]; } //else we're at steady state - do nothing. } } //write step LATC=stateMap[currentState]; if(dir==1) { currentState = (currentState + 1) % stateCount; } else { currentState = (currentState + 5) % stateCount; } t0Delay(curDelay); if(stepsAtThisSpeed>0)
{
stepsAtThisSpeed--;
}
stepsLeft--;
currentStep+=dir;
}
}
int main(void) {
init_io();
serial_init();
// set up oscillator control register, using internal OSC at 4MHz.
OSCCONbits.IRCF = 0x05; //set OSCCON IRCF bits to select OSC frequency 4MHz
OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
ADCON0 = 0b00100101; //select AN9 and enable
ADCON1 = 0b00000000; //speed Vref=AVdd, VssRef=AVss
ADCON2 = 0b00111011; //ledft justified, 20RAD, FRC
INTCONbits.TMR0IE = 0;
TMR0=0;
T0CONbits.T08BIT = 1;
T0CONbits.T0CS = 0;
T0CONbits.PSA = 0;
T0CONbits.T0PS = 0x04;
INTCONbits.TMR0IF = 0;
T0CONbits.TMR0ON = 1;
__delay_us(5);
currentStep = 0;
currentState = 0;
zeroMotor();
__delay_ms(149); //this could be less messy
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
moveMotor(20);
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
__delay_ms(149);
moveMotor(940);
moveMotor(5);
while (1) {
//PORTAbits.RA0 = 1; //heart beat
//__delay_ms(50);
//PORTAbits.RA0 = 0;
//__delay_ms(50);
ADCON0 = 0b00100101; //select AN9 and enable
__delay_us(5);
GO = 1;
while (GO) continue; //wait for conversion
an9_value = ADRESH; //AN9 value
fvar = an9_value;
fvar = fvar * 10749; //calibration.. change to meet your needs
fvar = fvar / 256;
tens = fvar / 100;
//tens = tens % 10;
decm = fvar % 100;
vtxdata = fvar / 20;
uart_xmit(vtxdata); // -->RS232
moveMotor(vtxdata);
//moveMotor(5); //from sample code
}
return (EXIT_SUCCESS);
}
Some ECCP ( Enchanced PWM ) code written for the PIC 18F26K22 code I wrote following the screen shot of the output: