Showing posts with label CCS. Show all posts
Showing posts with label CCS. Show all posts

Tuesday, April 21, 2009

Driving a Piezoelectric Speaker with a PIC

Piezoelectric speakers are really cool. You can get them inexpensively from most hobby electronics stores, take them out of PCs, and so on. You can directly connect them to your microcontroller (resistor recommended) and generate any tone you want.

Simply connect one end of the speaker to an output pin on your PIC and connect the other end to GND for the simplest configuration. You make the speaker “tick” by passing current through it. By rapidly turning the output pin on and off, you generate a tone. Here’s a very simple example program that turns the output pin on and off via software:

#include "main.h"
#define SLEEP 1000

void main() {
    setup_adc_ports(NO_ANALOGS|VSS_VDD);    
    setup_oscillator(OSC_8MHZ);
    setup_uart(9600);
    
    while(true) {
        output_high(PIN_B6);
        output_high(PIN_C0);
        delay_us(SLEEP);
        output_low(PIN_B6);
        output_low(PIN_C0);
        delay_us(SLEEP);
    }
}

Pin B6 (in my case) is the speaker output. Pin C0 is an output to an LED (for testing, it is not needed). You can change the value of the SLEEP define for varying frequency of sound.

However, there is another way that this can be done (more reliably) – using the PIC’s internal PWM (from CCP module). You can generate very precise frequencies that way.

Saturday, April 4, 2009

DS18B20 1-wire Driver for CCS C

I got my hands on a few of these DS18B20 1-wire digital temperature sensors. They’re really awesome. They’re small, easy to work with, and they run on the 1-wire bus which means they can run on a minimum of two wires. However, I found it easier to just run these devices with 3 lines: +5V, GND, Bus – saves a lot of design complexity.

I found a few good 1-wire drivers for CCS C (especially for these devices):

DS18S20 & DS18B20 Codes

One DS18B20 in powered mode

dallas onewire primitives library and ds1822 driver code

I then took ideas from them and made my own little driver. Some of the code is copied, some of it isn’t. Here it is:

main.c

#include "main.h"
#include "1wire.c"
#include "ds1820.c"

float value = 0.0;

void main() {
    setup_adc_ports(NO_ANALOGS|VSS_VDD);
    setup_adc(ADC_OFF);
    setup_spi(SPI_SS_DISABLED);
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED,0,1);    
    setup_oscillator(OSC_8MHZ);
    setup_uart(9600);
    
    delay_ms(1000);
    
    printf("Starting...\t\n");
    while(TRUE) {        
        value = ds1820_read();
        printf("%f\t\n", value);        
    }
}

main.h

#ifndef MAIN_H
#define MAIN_H

#include <16F690.h>
#device adc=8

#FUSES NOWDT                     //No Watch Dog Timer
#FUSES INTRC_IO                  //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT                 //Code not protected from reading
#FUSES NOBROWNOUT                //No brownout reset
#FUSES NOMCLR                    //Master Clear pin used for I/O
#FUSES NOCPD                     //No EE protection
#FUSES PUT                       //Power Up Timer
#FUSES IESO                      //Internal External Switch Over mode enabled
#FUSES FCMEN                     //Fail-safe clock monitor enabled

#use delay(clock=8000000)
#use rs232(baud=9600, parity=N, UART1, bits=8, stop=1)

#endif /*MAIN_H*/

1wire.c

#ifndef ONE_WIRE_C
#define ONE_WIRE_C

/*
 * One wire (1-wire) driver for CCS C compiler. Suitable for use with devices
 * such as the DS18B20 1-wire digital temperature sensor.
 */

#define ONE_WIRE_PIN PIN_C5

/*
 * onewire_reset()
 * Description: Initiates the one wire bus.
 */
// OK if just using a single permanently connected device
void onewire_reset() {
    output_low(ONE_WIRE_PIN);       // pull the bus low for reset
    delay_us(500);
    output_float(ONE_WIRE_PIN);     // float the bus high
    delay_us(500);                  // wait-out remaining initialisation window
    output_float(ONE_WIRE_PIN);
}


/*
 * onewire_write(int8 data)
 * Arguments: a byte of data.
 * Description: writes a byte of data to the device.
 */
void onewire_write(int8 data) {
    int8 count;

    for(count = 0; count < 8; ++count) {
        output_low(ONE_WIRE_PIN);
        delay_us(2);                // pull 1-wire low to initiate write time-slot.
        output_bit(ONE_WIRE_PIN, shift_right(&data, 1, 0)); // set output bit on 1-wire
        delay_us(60);               // wait until end of write slot.
        output_float(ONE_WIRE_PIN); // set 1-wire high again,
        delay_us(2);                // for more than 1us minimum.
    }
}

/*
 * onewire_read()
 * Description: reads and returns a byte of data from the device.
 */
int onewire_read() {
    int count, data;

    for(count = 0; count < 8; ++count) {
        output_low(ONE_WIRE_PIN);
        delay_us(2);                // pull 1-wire low to initiate read time-slot.
        output_float(ONE_WIRE_PIN); // now let 1-wire float high,
        delay_us(8);                // let device state stabilise,
        shift_right(&data, 1, input(ONE_WIRE_PIN)); // and load result.
        delay_us(120);              // wait until end of read slot.
    }
    return data;
} 

#endif /*ONE_WIRE_C*/

ds1820.c

#ifndef DS1820_C
#define DS1820_C

#include "1wire.c"

float ds1820_read();
void ds1820_configure(int8 TH, int8 TL, int8 config);

/*
 * ds1820_read()
 * Description: reads the ds18x20 device on the 1-wire bus and returns
 *              the temperature
 */
 
float ds1820_read() {
    int8 busy=0, temp1, temp2;
    signed int16 temp3;
    float result;
    
    //ds1820_configure(0x00, 0x00, 0x00);     //9 bit resolution

    onewire_reset();
    onewire_write(0xCC);            //Skip ROM, address all devices
    onewire_write(0x44);            //Start temperature conversion

    while(busy == 0)                //Wait while busy (bus is low)
        busy = onewire_read();

    onewire_reset();
    onewire_write(0xCC);            //Skip ROM, address all devices
    onewire_write(0xBE);            //Read scratchpad
    temp1 = onewire_read();
    temp2 = onewire_read();
    temp3 = make16(temp2, temp1);
 
    //result = (float) temp3 / 2.0;   //Calculation for DS18S20 with 0.5 deg C resolution
    result = (float) temp3 / 16.0;    //Calculation for DS18B20
 
    delay_ms(200);
    return(result);
}

/*
 * ds1820_configure(int8 TH, int8 LH, int8 config)
 * Description: writes configuration data to the DS18x20 device
 * Arguments: alarm trigger high, alarm trigger low, configuration
 */

void ds1820_configure(int8 TH, int8 TL, int8 config) {
    onewire_reset();
    onewire_write(0xCC);            //Skip ROM, address all devices
    onewire_write(0x4E);            //Write to scratchpad
    onewire_write(TH);
    onewire_write(TL);
    onewire_write(config);
}

#endif /*DS1820_C*/

All you have to do is set the define to the appropriate pin you’re using for the 1-wire bus. Remember to attach a 4.7k pullup resistor on the bus to VDD. The value of the pullup resistor is not critical. If I remember correctly, I tested resistors anywhere from 1k to 10k and they worked fine. If not, just stick with the 4.7k pullup as recommended in the DS18B20 datasheet.

Tuesday, March 10, 2009

SPI Modes in CCS C

When interfacing SPI devices, the appropriate SPI mode should be used. The SPI modes are described here in detail: http://en.wikipedia.org/wiki/Serial_peripheral_interface

Here are some easy to use defines for use with the CCS C compiler in the setup_spi() function:

#define SPI_MODE_0_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)    //SPI Mode 0
#define SPI_MODE_0_1  (SPI_L_TO_H)                      //SPI Mode 1
#define SPI_MODE_1_0  (SPI_H_TO_L)                      //SPI Mode 2
#define SPI_MODE_1_1  (SPI_H_TO_L | SPI_XMIT_L_TO_H)    //SPI Mode 3

Just put them in a header or source file somewhere and call setup_spi() like this:

setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_4);

Note that SPI Mode 0 is a typical SPI mode. The AS1107 uses it, for example. I think it’s the most common SPI mode.

Sunday, March 8, 2009

My First CCS Program – 16F690 on Low Pin Count Demo Board (PICKIT2)

Here’s my first real CCS program. It’s for the 16F690 on the low pin count demo board that comes with the PICKIT2. All this program does is read the voltage on RA0 provided by the trimpot and show the 4 most significant bits of the result on the LEDs. Simple, elegant, easy and it works. CCS is really cool once you get it set up the way you like.

 

Source: http://pastebin.com/f3516334c

Header: http://pastebin.com/f796e3258

CCS Annoyance Update

Update: the progress popup window can be suppressed. Just go to Project Options > Output Files and you’ll see the option. You can even make it default for new projects. Source: Matt Pobursky from the PICLIST.

More About CCS C Compiler

  • When compiling a project, an annoying progress dialog pops up and stays for a few seconds after the compilation process has completed. Annoying.
  • CCS C compiler integrates well into MPLAB, so you can bypass the annoyance above. However, MPLAB does not come with the awesome project wizard, which brings us to our next point:
  • The project wizard doesn’t let you make modifications to your existing project. It only lets you create a new one.

Monday, March 2, 2009

CCS C compiler is not as bad as I thought…

In the past, I had believed that the two best C compilers for PIC microcontrollers were made by HI-TECH and Microchip. I didn’t give much thought to CCS C as there are many other PIC C compilers in the market. I was pleasantly surprised when I gave CCS C a try.

 

Pros:

  • Very easy to get started with and use.
  • Produces compact code.
  • Huge built in library of functions for peripherals and so on.
  • Large user-submitted forum code library and large user base.
  • Great support for many PIC devices from the low end 12 bit PICs (PIC10F) to the 14 bit PICs (PIC12F, PIC16F) to the high end PICs (PIC18F) to the DSPICs.
  • Powerful command line interface for the compiler.
  • Runs on Windows and Linux natively, (no need for WINE). However, the Linux version is lagging behind two updates (Linux: 4.085; Windows: 4.087).
  • MPLAB integration.
  • Well documented user manual – easy to read and understand.
  • Good support for data types, but could be improved (for example, by adding 64 bit data types).

Cons:

  • Horrible, ugly, and otherwise inaccessible and intrusive user interface. Although beauty is in the eye of the beholder, I strongly believe that they could have made their IDE more pleasant to use by:
    • Using a standard widget set and not their horrible custom MS Office 2007 knock-off.
    • Making things easier to access by placing accessible buttons that perform common actions (open datasheet, open compiler manual, etc.)
  • Can be buggy sometimes and can be frustrating when you’re searching for a problem in your code and it’s actually the compiler’s fault. The CCS team needs to be a bit more careful with their updates.

 

All in all, the extensive code library and shallow learning curve make this compiler very suitable for hobby projects where you can actually spend time working on your project and not worrying about hunting down libraries or writing lengthy drivers.