<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Project Notes &#187; PWM</title>
	<atom:link href="http://projectnotes.co.uk/tag/pwm/feed/" rel="self" type="application/rss+xml" />
	<link>http://projectnotes.co.uk</link>
	<description>Random Computer, Internet and Electronics Projects</description>
	<lastBuildDate>Fri, 06 Jan 2012 13:43:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>PWM function in 16F876 I/O Processor</title>
		<link>http://projectnotes.co.uk/2008/08/pwm-function-in-16f876-io-processor/</link>
		<comments>http://projectnotes.co.uk/2008/08/pwm-function-in-16f876-io-processor/#comments</comments>
		<pubDate>Fri, 29 Aug 2008 00:25:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Blassic]]></category>
		<category><![CDATA[I/O Bus]]></category>
		<category><![CDATA[I2C]]></category>
		<category><![CDATA[OpenWrt Midge]]></category>
		<category><![CDATA[16F876A]]></category>
		<category><![CDATA[PWM]]></category>

		<guid isPermaLink="false">http://www.projectnotes.co.uk/?p=116</guid>
		<description><![CDATA[I have added a basic PWM service to the PIC 16F876 I2C Slave I/O Processor.  Here is the updated JAL Source and a Blassic program for the Router.  It reads the Analog input, and prints to the console or sounds &#8230; <a href="http://projectnotes.co.uk/2008/08/pwm-function-in-16f876-io-processor/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have added a basic <strong>PWM</strong> service to the <strong>PIC 16F876</strong> <strong>I2C</strong> Slave I/O Processor.  Here is the updated <strong>JAL</strong> Source and a <strong>Blassic</strong> program for the Router.  It reads the Analog input, and prints to the console or sounds a Beep using the <strong>PWM</strong> output.<span id="more-100"></span></p>
<h2>Updated JAL Source for the 16F876 I/O Processor</h2>
<pre>-- Sebastien Lelong Copyright (c) 2008, http://sirloon.net
--
-- This file is part of the Sirbot Project (http://sirbot.org)
-- Released under the GPL license
--

-- !! changes by Phill, ProjectNotes.co.uk for
-- use with the 16F876a as an I/O extender for the Midge/OpenWrt
-- &amp; Sunspot software driven routers.

-- 29/08/08 Added basic PWM support and I/O Command List
-- At Reset, PWM is set to 50% (2.5v)

-- I/O Commands
-- 01 - Write Next byte to Port B
-- 02 - Write Next Byte to H/W Serial Port
-- 03 - Next Read Byte is Latest Serial Port Rx Data OR ZERO
-- 04 - Next Read Byte is Analog in From Pin A0
-- 05 - Toggle Output Pin A1 (status led?)
-- 06 - Write Next Byte to Jal PWM  Duty Cycle

-- Once a read data command has been sent, it will star in effect until
-- another command has been sent.
-- After a Write data or immediate command (05) is complete, the command
-- byte is set to zero (ready for another command)

include 16F876a_bert

--include sb_config
--include sb_protocol
--include sb_mainboard

-- !! 16F876a port C3&amp;4 are the I2C i/o pins
-- AppNote says must be configured as input first
--pin_b4_direction = input
--pin_b1_direction = input
pin_c6_direction = output -- tx
pin_c7_direction = input  -- rx
pin_c3_direction = input
pin_c4_direction = input

-- For testing purpose (checking if slave is responding to START/STOP signals)
-- you may want to activate 7bits address with interrupts (see spec)
;;SSPCON = 0b_0011_1110	-- slave 7bit address, start/stop interrupt
SSPCON = 0b_0011_0110	-- slave 7bit address

-- I2C slave hardware
-- Careful: we're in 7bits i2c address, *but* PIC
-- wants an address coded on 8bits, that is, with read/write bit
-- In master, slave address is:
-- 		0x2E &lt;=&gt; 0b_0010_1110
-- So, in slave, by left-shifting once, we have:
--		0x5C &lt;=&gt; 0b_0101_0110
SSPADD = 0x5C

-- init SSPSTAT
BF = false
WCOL = false
SSPOV = false
SSPIF = false
-- enable interrupts
SSPIE = true
GIE = true
PEIE = true

-- !! no ready/busy leds, we want port B all OUT
-- "Ready !" LED
-- var bit ready_led_direction is pin_b0_direction
-- var bit ready_led is pin_b0
-- ready_led_direction = output
-- Error LED
-- var bit error_led_direction is pin_b3_direction
-- var bit error_led is pin_b3
-- error_led_direction = output

var byte tmpstat
var byte tmpbuf
var byte data

-- !! add a few temp registers of our own
var byte serialtemp
var byte command
var bit a1f
command = 00
a1f = off
-- !! set up our a1 toggle bit
pin_a1_direction = output
pin_a1 = a1f
-- !! set up our adc in pin
pin_a0_direction = input

-- !!

-- test to set SSPBUF to see if it's changed while receiving
-- the first byte address
SSPBUF = "A"

function read_i2c() return byte is
	tmpbuf = SSPBUF
	return tmpbuf
end function

procedure write_i2c(byte in what) is
	-- wait 'til buffer is empty
	while BF loop end loop
	var bit dosend = true
	while dosend
	loop
		WCOL = false
		-- try to write into buffer, checking collision
		SSPBUF = what
		if ! WCOL
		then
			-- ok, done
			dosend = false
		end if
		-- else continue trying
	end loop
    CKP = 1
end procedure

procedure proceed_state_1() is
	-- state 1:write operation, last byte is address, buffer full
	-- byte is an address, it we get here, we just know master
	-- wants to talk to us...
	-- and we also know address is recognized (BF is set, see spec)
	-- anyway, we must read buffer to reset BF bit
	read_i2c()
end procedure

procedure proceed_state_2() is
	-- state 2: write operation, last byte is data, buffer full
	-- got data, need to echo char + 1
	data = read_i2c()
	-- ultimate data processing... <img src='http://projectnotes.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
  -- !! here do something useful
  if command == 01 then
  portb = data
  data = 0
  end if
  if command == 02 then
  serial_hw_write(data)
  data = 0
  end if
  if command == 06 then

  PWM_set_dutycycle (data,data)
  data = 0
  end if
  command = data -- Not in a command, this must be a command.
  -- if we don't handle it here, it may be a read data command
  if command == 05 then
  a1f = ! a1f
  pin_a1 = a1f
  command = 0 -- done with this command
  end if

end procedure

procedure proceed_state_3() is
	-- state 3: read operation, last byte is address, buffer empty
	-- master wants to get a value from us

  --!! decide what data to return
  if command == 03 then
  data = serialtemp -- last serial rx char
  serialtemp = 0 -- clear it
  end if
	if command == 04 then
	data = ADC_read_low_res(0)
	end if
	write_i2c(data)
end procedure

procedure proceed_state_4() is
	-- state 4: read operation, last byte is data, buffer empty
	-- master still wants to get a value from us
	write_i2c(data)
	-- note: this shouldn't occur
end procedure

procedure proceed_state_5() is
	-- state 5: nack
	-- master doesn't want to talk with us anymore
	-- reset slave logic
	-- AN734 does not talk about setting CKP, whereas spec says
	-- it must be set. Some people say it can be error prone.
    CKP = 1
	data = 0
end procedure

procedure proceed_error() is
	-- something went wrong, that is, XOR operations did not match
	-- SSPSTAT bits
	-- Just log current status
	serial_hw_write("E")
	serial_hw_write(SSPSTAT)
end procedure

procedure ssp_handler() is
	pragma interrupt
	if SSPIF
	then
		SSPIF = false
		tmpstat = SSPSTAT
		-- mask out unimportant bit
		tmpstat = tmpstat &amp; 0b_0010_1101
		-- check state 1: write operation, last byte is address, buffer full
		if (tmpstat ^ 0b_0000_1001) == false
		then
			proceed_state_1()
		-- check state 2: write operation, last byte is data, buffer full
		elsif (tmpstat ^ 0b_0010_1001) == false
		then
			proceed_state_2()
		-- check state 3: read operation, last byte is address, buffer empty
		elsif (tmpstat ^ 0b_0000_1100) == false
		then
			proceed_state_3()
		-- check state 4: read operation, last byte is data, buffer empty
		elsif (tmpstat ^ 0b_00101100) == false
		then
			proceed_state_4()
		-- check state 5: nack
		elsif (tmpstat ^ 0b_0010_1000) == false
		then
			proceed_state_5()
		-- check only got a start signal (when using interrupts)
		else
			proceed_error()
		end if
	else
		-- another interrupt. Weird...
--		ready_led = low
--		delay_10ms(100)
--		ready_led = high
		serial_hw_write("*")
	end if
end procedure
-- don't need status leds
--ready_led = low

--error_led = high
--delay_10ms(30)
--error_led = low
--delay_10ms(30)
--error_led = high
--delay_10ms(30)
--error_led = low
--delay_10ms(30)
--error_led = high
--delay_10ms(30)
--error_led = low

--ready_led = high

-- 29/08/08 add PWM support
pin_c2_direction = output
PWM_init_frequency (true,true)
PWM_set_dutycycle(128,128)

forever loop
	-- just loop until interrupt is raised
	-- !! poll the serial port

	if RCIF then
    serial_hw_read(serialtemp)
    serial_hw_write(serialtemp) -- echo to confirm hardware is working!
 end if

end loop</pre>
<p>Next, the Blassic source</p>
<h2><!--more-->AnalogLightWarn.bas</h2>
<p>The following <strong>Blassic</strong> program uses the <strong>PIC 16F876a</strong> <strong>I2C</strong> I/O processor to monitor a solar panel (1.5v max!) If the light reading changes by less than 2 up or down, no action is taken.</p>
<p>If the light increases by more than 2, a message is sent to the console.</p>
<p>If the light decreases by more than 2, a beep is sounded via a small speaker connected to the PWM output pin (Port C,2).</p>
<p>As the speaker is only 8 ohms, a 47 ohm resistor and 1uf capacitor are inline to limit the current through the speaker coil.</p>
<p>The Tone of the beep is quite low, this is because of the speed of the basic interpreter AND the time it takes to send 4 bytes of instruction via the I2C Interface.</p>
<p>Later I will look at using an alternative method of sending data to the 16F876 via two other led lines, simply clocking out the required data.</p>
<pre>     10 REM Read the Analog Input A0
     15 REM if the level is a lot different from last time, say helo
     20 REM
     30 REM I2C Control
     40 I2CAddress=34
     50 I2CData=35
     60 PIC16F876=46 : REM Address of Our Chip
     70 REM Commands
     80 AnalogRead = 4
     90 PortA1Invert = 5 : REM Invert A1
    100 REM Begin
    105 last=0
    110 POKE I2CAddress,PIC16F876 : REM Address the chip
    120 POKE I2CData,AnalogRead
    130 a = PEEK(I2CData)
    135 REM PRINT a
    140 POKE I2CData,PortA1Invert
    150 IF ((a&gt;last) AND (a-last &gt; 2)) THEN GOSUB 300
    160 IF ((a&lt;last) AND (  last-a &gt; 2)) THEN  GOSUB 400
    165 last = a : REM remember for next time
    170 REM pause
    180 FOR x=0 TO 1000: NEXT
    190 GOTO 120
    300 REM lighter
    310 PRINT "Lighter"
    320 RETURN
    400 REM Darker
    410 FOR N=1 TO 30
    420 POKE I2CData,6 : POKE I2CData,255 : REM PWM=0v
    430 POKE I2CData,6 : POKE I2CData,0 : REM PWM = 5v
    450 NEXT N
    460 RETURN
Ok</pre>
]]></content:encoded>
			<wfw:commentRss>http://projectnotes.co.uk/2008/08/pwm-function-in-16f876-io-processor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

