Home
| pfodApps/pfodDevices
| WebStringTemplates
| Java/J2EE
| Unix
| Torches
| Superannuation
|
| About
Us
|
Android™ Controlled LED Driver using pfodApp™
|
by Matthew Ford 22nd April 2011
©
Forward Computing and Control Pty. Ltd. NSW Australia
All rights
reserved.
Part 1 of the tutorial introduced pfodDevices and the covered the specification of the operation discovery protocol. Part 2 of this tutorial covered the mobile phone pfodApp. Part 3 covered the design and testing of the pfodDevice messages that the Led Controller would support.
This part of the tutorial covers the code changes need to turn the RemoteLedDriver into a pfodDevice. As a pfodDevice, the Led Controller will advertise its functionality to the pfodApp and let the user control the Led. For the Led Controller this functionality will include fading the led on and fading it off, increasing and decreasing the brightness and two sub-menus, one to set specific levels, High, Med, Low and another to display the current level setting and led current.
The complete code for the Led Controller pfodDevice can be downloaded from pfodLedDriver.asm That code is based on the previously described RemoteLedDriver.asm code. This part of the tutorial will only cover the differences. Please refer to the previous tutorials, Mobile Phone Controlled Led Driver and Bluetooth Controlled Led Driver for descriptions of the other parts of the code.
The main difference between the
RemoteLedDriver and the pfodLedDriver is in the way the incoming
serial data is handled. Based on the message design done in Part
3 of this tutorial, the pfodLedDriver needs to be able to parse
and handle each of the following messages
{.}
{o} {f} {u} {d} {l} {a} {0} {1} {2} {3} {i} {v} {m}
This is done in three
stages
1) process the received characters looking for the
starting { character, the command character and the
terminating } - PROCESS_RECEIVED_CHAR
2) execute the
command - PROCESS_CMD_CHAR
3) send back a response message to the
pfodApp so that the pfodApp knows the command has been received and
executed. - SEND_...
PROCESS_RECEIVED_CHAR:
cpi Temp, '{' //
breq PROCESS_RECEIVED_START_CMD
cpi Temp, '}' //
breq PROCESS_RECEIVED_END_CMD
// else save last char
tst commandCharacter
brne RET_PROCESS_RECEIVED_CHAR
// else save the first
mov commandCharacter,Temp;
rjmp RET_PROCESS_RECEIVED_CHAR
PROCESS_RECEIVED_START_CMD:
clr commandCharacter // clear on msg start
rjmp RET_PROCESS_RECEIVED_CHAR
PROCESS_RECEIVED_END_CMD:
mov Temp, commandCharacter
rcall PROCESS_CMD_CHAR // process the cmd
ldi commandCharacter, -1 // finished processing
RET_PROCESS_RECEIVED_CHAR:
ret
This routine is called for each character received on the RS232 Rx pin (see Coding the RS232 Module for details). The received character is in the Temp register. When the message start character { is received the commandCharacter is cleared. Then then next character is saved as the commandCharacter. Any further character before the closing } are ignored. When the message termination character } is received then the saved commandCharacter is loaded into the Temp register and PROCESS_CMD_CHAR is called to execute the command. Finally the commandCharacter is set to -1 to prevent any character outside the message start { and end } characters being saved as a command character.
The PROCESS_CMD_CHAR routine starts with a long switch statement which jumps to the appropriate label to handle that command. If the command is not recognized then the Led Controller just sends back an empty command { } to let the pfodApp to let it know it is connected. Since the pfodApp should only ever send commands that the Led Controller as advertised, this should not normally happen.
PROCESS_CMD_CHAR:
cpi Temp, 'o' // turn on/off
breq PROCESS_RECEIVED_ON_OFF
cpi Temp, 'f' // fade on/off
breq PROCESS_RECEIVED_FADE_ON_OFF
...
other commands here ...
cpi Temp, 'i' //
breq PROCESS_RECEIVED_CHAR_SEND_ADC_READING
cpi Temp, 'v' //
breq PROCESS_RECEIVED_CHAR_SEND_LIGHT_LEVEL
// else invalid char so just ignore
// send back {}
rjmp PROCESS_RECEIVED_CHAR_SEND_EMPTY_CMD
There are three types of commands. Those that just send back data, either menus or the streaming raw data message {=} plus data (i e. {.} {l} {a} {i} {v}, {m}), those that just set a level (i e. {u} {d} {0} {1} {2} {3} ) and those that toggle depending on the current state (i .e. {o} {f} )
The commands that send back data or menus just set the appropriate flags to trigger the respective SEND_ routine to send the menu or data. For example
PROCESS_RECEIVED_MAIN_MENU:
// set flag to send menu
sbr CMDS, (1<<CMDS_MainMenu)
rjmp END_PROCESS_CMD_CHAR
Then in the MAIN_LOOP, when the SEND_MAIN_MENU routine is called, the main menu response is sent back to the pfodApp. There are three main menu messages defined one for when the led is off or fading down and one for when it is on but is not at it maximum level and one for when the led is at its maximum setting.. The BRANCH_IF_TORCH_OFF_OR_FADING_DOWN and BRANCH_IF_TORCH_NOT_MAX macros is used to choose the appropriate response menu to send back.
The MAIN_LOOP is
MAIN_LOOP:
mov New_TORCH_State, TORCH_State // set initial state
rcall PROCESS_RS232 // process char if there is one
// and process cmd if } received
rcall LED_CONTROL_PROCESSING // each time ADC completes and save value
rcall UPDATE_TORCH_STATE // transfer new state to TORCH_State and update setpoint etc.
//
// now call all the message routines
// they will just return if nothing set to send
rcall SEND_EMPTY_CMD // send this first if set
rcall SEND_MAIN_MENU
rcall SEND_ONOFF_UPDATE
rcall SEND_SET_MENU
rcall SEND_DATA_MENU
rcall SEND_SUB_MENU
rcall SEND_STREAMING_CMD
rcall SEND_LEVEL // send level
rcall SEND_LIGHT // then % light
rcall SEND_ADC_READING // send Amps if needed
rjmp MAIN_LOOP
As in the Bluetooth Controlled Led Driver , this MAIN_LOOP just runs continually processing characters received from the RS232 input, controlling the Led each time there is a new current measurement and acting on the trigger flags set by the push button debounce code and the PROCESS_RS232 routine. Each SEND_... routine is controlled by its own flag. If the flag is set then that message is sent back to the pfodApp. The PROCESS_CMD_CHAR and its support routines set the appropriate flag depending on the command received and the torch state.
In a number of places in the code we need to check if the led is currently on or off so that the correct toggle action is taken or the correct menu update is sent. We define the led as being off if either it is off or it is fading down. If it is fading down it will be off very soon. The BRANCH_IF_TORCH_OFF_OR_FADING_DOWN macro is similar to other BRANCH_ macro described in earlier tutorials and will branch to the label argument if the torch is either off or fading down. Otherwise the program flow continues to the next statement.
The commands that just set a level (i e. {0} {1} {2} {3} ) just set that level e.g.
PROCESS_RECEIVED_CHAR_TORCH_HIGH: // 3 == high
ldi New_TORCH_State,Torch_State_HIGH
rjmp PROCESS_RECEIVED_CHAR_UPDATE
The up and down commands (i e. {u} {d} ) set the torch state to variable and then increment or decrement the level e.g.
PROCESS_RECEIVED_CHAR_TORCH_UP:
ldi New_TORCH_State, Torch_State_VARIABLE
// clear levels
rcall SHIFT_DOWN_LEVEL
inc Level
rcall SHIFT_UP_LEVEL
sbr CMDS, (1<<CMDS_OnOffUpdate)
rjmp END_PROCESS_CMD_CHAR
The call to SHIFT_DOWN_LEVEL and SHIFT_UP_LEVEL are there convert between the 10 user selectable levels and the 40 levels used for fad on and fad off. (e.g.)
//-------------------------------------
// Shift down level
// When get u or d cmd want to move level by 4
// so there is only 10 steps between off and MaxLevel 40
// this routine divides by 4 before the level is
// inc or dec
// -----------------------------------
SHIFT_DOWN_LEVEL:
push Temp
ldi Temp, Level_Shift
tst Temp
breq END_SHIFT_DOWN_LEVEL // nothing to do
SHIFT_DOWN_LEVEL_LOOP:
lsr Level
dec Temp
tst Temp
brne SHIFT_DOWN_LEVEL_LOOP
END_SHIFT_DOWN_LEVEL:
pop Temp
ret
The SHIFT_DOWN_LEVEL routine divides the Level register by 4 before it is incremented or decremented. The similar SHIFT_UP_LEVEL then multiplies the Level register by 4 again to scale the Level register back into the range 0 to maxLevel (40) These 40 levels are then mapped to an approximately logarithmic scale of current settings, via the Log_SetPoint table, to more closely match the eye's perception of brightness.
Log_SetPoint:
// this maps levels into current setpoints between 0 and 1000 (max ADC count is 1024)
// 0 == 0, 1==16 2==24 3 == 40
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
.dw 0, 1, 1, 2, 2, 3, 3, 5, 6, 7, 8, 10, 12, 15, 18, 21, 26, 32, 38, 47, 57
// 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
.dw 70, 86, 105, 129, 156, 188, 226, 273, 319, 373, 436, 509, 569, 636, 710,794, 841, 891, 944,1000
When the CMDS_OnOffUpdate flag is handled by SEND_ONOFF_UPDATE routine called from the MAIN_LOOP, the SEND_ONOFF_UPDATE routine checks the current level and state of the torch and chooses the correct update to send to the navigation menu.
The On/Off and FadeOn/FadeOff commands ({o} {f} ) are toggles. That is each time the command is received by the pfodDevice, the pfodDevice toggles the state from on to off or from fadeOn to fadeOff.
The on/off processing looks checks the current Led state using the BRANCH_IF_TORCH_OFF_OR_FADING_DOWN macro, and then sets the Led either off or to Low. The FadeOn/FadeOff processing is similar except that it set the torch state to either Torch_State_FADE_UP or Torch_State_FADE_DOWN.
In the background the TIMER_FADE routine is called every 2mS using the same timer the switch debounce uses. Each time it is called if the FADE_COUNTER has reached zero and torch is in a fadeOn or fadeOff state, the TRIGGER_FADE flag is set and the FADE_COUNTER is reloaded. If fading up, 6 counts are used. If fading down 12 counts are used so that the fade down is twice as slow as fading up.
//--------------------------
// TIMER_FADE:
// Called from TIMER1_2mS each 2 mSec
// FadeUp counts to 6
// FadeDown counts to 12
// 40 steps => 0.5 sec up and 1sec fade down
//-------------------------
TIMER_FADE:
lds Temp, FADE_COUNTER
dec Temp
brpl END_TIMER_FADE
// else == 0
ldi Temp, 1 // for next dec unless updated below
cpi Torch_State, Torch_State_FADE
brlo END_TIMER_FADE // not fade just load 1 in counter
// else set trigger
sbr TRIGGER_Flags, (1<<TRIGGER_FADE)
ldi Temp,Fade_Count_Up // reload
cpi Torch_State, Torch_State_FADE_UP
breq END_TIMER_FADE // load up timer
// else down
ldi Temp,Fade_Count_Down
//rjmp END_TIMER_FADE // drop through
END_TIMER_FADE:
sts FADE_COUNTER, Temp
ret
The TRIGGER_FADE flag is examined in the PROCESS_SWITCH_STATE_TRIGGER routine which is called from the MAIN_LOOP via the LED_CONTROL_PROCESSING routine. If the TRIGGER_FADE flag is set then the FADE routine is called.
//--------------------------------------
// FADE
// called every time FADE_TRIGGER is set
// if Torch_State_FADE_UP increase level
// if Torch_State_FADE_DOWN decrease level
// if not FADE do nothing
//
//--------------------------------------
FADE:
push Temp
cpi Torch_State, Torch_State_FADE
brmi END_FADE // not fading so return
cpi Torch_State, Torch_State_FADE_UP
breq FADE_FADE_UP
// else fade down
FADE_FADE_DOWN:
dec Level
rcall LOAD_SETPOINT_FROM_LEVEL
rjmp END_FADE
FADE_FADE_UP:
inc Level
rcall LOAD_SETPOINT_FROM_LEVEL
// rjmp END_FADE fall through
END_FADE:
pop Temp
ret
The FADE routine checks the torch state and increases or decreases the level as appropriate. The LOAD_SETPOINT_FROM_LEVEL routine cleans up levels that are <0 or > maxLevel.
This completes a full implementation of pfod (Protocol for Operations Discovery). Under the pfod protocol, the pfodDevice™ advertises its capabilities to the pfodApp™ so the same pfodApp can be used to control any pfodDevice. The pfod protocol is very simple with minimal message structures and is readily implemented by small micro-processors such as the Atmel ATTINY series.
The first section presented the definition of the pfod protocol. The second section presented a functioning implementation of a pfodApp for a Android mobile. The pfodApp is universal to all pfodDevices and allows multiple devices with different capabilities to be controlled from this one application. The third section covered the design of the pfodDevice commands for a sample LED driver. The last section built on the previous Bluetooth Controlled Led Drive and modified the code to make the LED controller a pfodDevice.
The General Purpose Android/Arduino Control App.
pfodDevice™ and pfodApp™ are trade marks of Forward Computing and Control Pty. Ltd.
Contact Forward Computing and Control by
©Copyright 1996-2020 Forward Computing and Control Pty. Ltd.
ACN 003 669 994