You are on page 1of 27

THE UNIVERSITY OF NOTTINGHAM

SCHOOL OF ELECTRICAL AND


ELECTRONIC ENGINEERING

H63ECH coursework

GROUP 11

Assignment 1 (Morse code) 4068184

Assignment 2 (Safety controller) 4085517

Assignment 3 (Volume controller) 4074719

Assignment 4 (Binary calculator) 4072770

DATE submitted 8 December 2009

Coursework submitted in part fulfilment of the requirements of the H63ECH module.


2009
-

Author:
4068184

H63 ECH – Task 1 Morse Code

[THE UNIVERSITY OF
NOTTINGHAM EEE SCHOOL]
EMBEDDED COMPUTER HARDWARE - H63ECH
PIC PROGRAMMING COURSEWORK
Student ID - 4068184
Group 11 – Question 1 – Morse code

TASK 1

The basis of task 1 part A is to create a super loop which continually checks for user input and then based on
that input performs a certain operation. The specification states that SW1 Sends the message, SW2 or SW3
(Separate) sets the send count to 2, SW2 and SW3 pressed together sets the send count to 3 and finally SW4
determines the message to be sent.

The size of this program has been have reduced by incorporating functions for repeated sections of code. For
example, by defining the process of flashing S as a function, it is not necessary to have the code to flash S
repeated out multiple times. Instead it can be called when needed, reducing the size of the program memory.
This has been applied to all of the letters that can be transferred.

The task was successful, and the developed code ran perfectly in testing and in practice. The user of the PIC
can select between STOP and SOS signals, they can choose to send it 2 or 3 times and then send the message.
The device will reset after the particular message has been sent the predetermined amount of times, ready for
the next set of transmissions.
TASK 2
Program memory size = 61

Code Listing for CCP Initiation and settings in program.asm

CCPInit

clrf T1CON ;Reset T1CON


movlw B'00110000' ;Set up Timer1, Prescaler = 8
movwf T1CON

clrf CCP1CON ;Reset CCP

movlw 0x0B ;Select Comparator with Timer1 Reset


movwf CCP1CON;

movlw B'11000011' ;Set Count Limit by setting both High and Low
byte of CCPR1
movwf CCPR1H ;Set to 50,000
movlw B'01010000'
movwf CCPR1L

clrf TMR1H ;Clear TMR1 (High and Low)


clrf TMR1L

bsf T1CON, TMR1ON ;Enable Timer1 On

Code Listing for Super Loop in program.asm

L1
btfsc PIR1, CCP1IF
goto LEDOn
goto L1
LEDOn
bsf LEDs, LD6
bcf PIR1, CCP1IF

TASK 3
Program Memory Size = 74

Code Listing for ISR and functions in program.asm

ISR
bcf PIR1, CCP1IF ;Clear CCP Interrupt Flag from PIR1
bsf LEDs, LD3 ;Turn on LED3
bsf LEDToggle,0 ;Toggle

retfie
LEDSwitch

btfsc LEDs,LD6 ;Check current LED Setting


goto LEDOff ;Go to Off function
bsf LEDs,LD6 ;Turn LED6 On
bcf LEDToggle,0 ;Clear Flag
goto MLoop

LEDOff

bcf LEDs,LD6 ;LED6 Off


bcf LEDToggle,0 ;Clear Flag
goto MLoop

Code Listing for CCP Initiation and settings in program.asm

CCPInit

clrf T1CON ;Reset T1CON


movlw B'00110000' ;Set up Timer1, Prescaler = 8
movwf T1CON

clrf CCP1CON ;Reset CCP

bsf STATUS, RP0 ;Select Bank 1


bsf PIE1, 2 ;Enable CCP Interrupt on Peripheral Interrupt Register

bcf STATUS,RP0 ;Select Bank 0


movlw 0x0B ;Select Comparator with Timer1 Reset
movwf CCP1CON;

movlw B'11000011' ;Set Count Limit by setting both High and Low byte of CCPR1
movwf CCPR1H ;Set to 50,000
movlw B'01010000'
movwf CCPR1L

clrf TMR1H ;Clear TMR1 (High and Low)


clrf TMR1L

movlw B'11000000' ;Enable General and Peripheral Interrupts


movwf INTCON

bsf T1CON, TMR1ON ;Enable Timer1 On

Code Listing for Super Loop in program.asm

btfsc LEDToggle,0
goto LEDSwitch
TASK 4
Program Memory Size = 281

Code listing for proba.c

#include <htc.h>
#include "inclC.c"

#define LEDs PORTB


#define SWs ReadSw()

FlashS() { //Function to flash S


LEDs = 0b00000001;
DelWds(2);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(2);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(2);
LEDs = 0b00000000;
}

FlashO() { //Function to flash O


LEDs = 0b00000001;
DelWds(6);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(6);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(6);
LEDs = 0b00000000;
}

FlashT() { //Function to flash T


LEDs = 0b00000001;
DelWds(6);
LEDs = 0b00000000;
}

FlashP() { //Function to flash P


LEDs = 0b00000001;
DelWds(2);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(6);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(6);
LEDs = 0b00000000;
DelWds(2);
LEDs = 0b00000001;
DelWds(2);
LEDs = 0b00000001;
}

SendSOS() { //Function to Send SOS


FlashS();
DelWds(6);
FlashO();
DelWds(6);
FlashS();
}

SendSTOP() { //Function to send stop


FlashS();
DelWds(6);
FlashT();
DelWds(6);
FlashO();
DelWds(6);
FlashP();
}

main () {

unsigned char Count; // Count Variable


unsigned char MessageSwitch;
unsigned int i;

// configure pins
ADCON1 = 0b00000110; // disable ADC inputs
PORTB = 0;
TRISB = 0b11000000; // configure RB5..RB0 for output

// LEDs on for 0.3 s - test the LEDs work


LEDs = 0b00111111;
DelWds (3);

Count = 1; //Init Count

// superloop - here copy switches (PORTA) to LEDs (PORTB)


while (1) {
switch(SWs) {
case 0b00000001 : //Case SW1, Send Message
for(i=0; i<Count; i++) { //For Count
if(MessageSwitch) { //SOS or STOP?
SendSOS();
} else if(!(MessageSwitch)) {
SendSTOP();
}
}
break;
case 0b00000010 : //Case SW2, Count = 2
Count = 2;
break;
case 0b00000100 : //Case SW3, Count = 2
Count = 2;
break;
case 0b00000110 : //Case SW2 + SW3, Count = 3
Count = 3;
break;
case 0b00001000 : //Case SW4, MessageSwitch=1
if(MessageSwitch == 0) {
MessageSwitch = 1;
}
break;
}
}
}

COURSEWORK QUESTION
Evaluate the Bit Rate for this sort of communication:

Binary Code for SOS Transmission: 101010001110111011100010101


Every binary digit lasts 0.2 seconds, assuming a dot is one bit high, a pause is 3 bits low and a dash is 3bits high

Therefore in bits per second, this communication method has an effective bit rate of 5 bits/second
ADDITIONAL TASKS FOR COURSEWORK
1. Implement an advanced ISR that backs up SFR and performs a task such as calculating the difference
between two bytes and setting up the LEDS to show the difference
2. A different principle task that I would be keen to see would be interfacing actuators (Motors, Servo’s
(using PWM)) so that the program could drive a small robot for example. This example would use the
CCP Module and Timer modules.

TESTING OF COURSEWORK PART 4


Testing of binary calculator successful. Program responds with correct keys and the result of the operation is
correct. The device does not encounter any glitches at the end of the cycle.
2009
-

Author:
4085517

H63 ECH – Task 2 Safety Controller

[THE UNIVERSITY OF
NOTTINGHAM EEE SCHOOL]
Embedded Computer Hardware - H63ECH
Student ID - 4085517

Assignment 2: Safety controller + generating the delay of 1 ms using TMR0


Introduction: This assignment has divided in to 4 tasks which using assembly
language programming for a PIC microcontroller. The first task is to simulate the
event of children enter the flume for prevent any accident that may have happen
by showing error. The second and third task is independent to the first task
which is generating a delay and interrupt. The last task is converting the code
from task 1_A to Embedded C.

Task 2_A
Design approach:
The input of this task is pushbuttons SW1-SW4 which control the output
and indicate the status by the LEDs (LD1, LD5, and LD6). LD5 will be on if there
is a child in flume. LD6 is indicating that there is no child in the flume and LD1 is
blinking if any child moves backward. At the beginning the LD6 should be on to
indicate that it is safe to enter the flume. SW1 is pressed if a child enters the
flume and LD6 should be off and LD5 should be on instead to indicate that there
is a person in the flume. If SW2 is pressed it means that a child is half way and
LD status should not change. If SW4 is pressed in this process it will reset the
board to first state. Now it will check the input continue from last state. If SW3
is press in this state it will indicate that a child leave a flume then LD5 will be off
and LD6 will be on again which indicate that the flume is safe to enter again but
if SW1 is press it will trigger alarm. From the above statement it can be shown
as a following diagram.

SW2,3,4

STATE1
LD6

SW4
SW4 SW1

STATE2 ALARM
SW3,4 LD5 LD1 SW1,2,3
SW1,3 blinking

SW2

STATE3 SW1
LD5

SW2

Figure 1: State Diagram of the program


The main code should contain the checking process and the output of that
state. The first main code will start at first state and check for the input of SW1
and then it will create some delay then go to state 2. Apart from SW1 input will
stay in the same state. The design of this state is show below.

STATE1 Delay STATE2 Figure 2: State1


LD5 off SW1 LD5 on flowchart
LD6 on LD6 off

Then second part should check for input SW2 and then create some delay and
go to state3. If it detects input of SW1 it will go to this part again but if it
detects SW3 it will trigger alarm. The design of this state is show below.

Figure 3: State2
STATE2
SW2
Delay STATE3 flowchart
LD5 on LD5 on
LD6 off LD6 off

The third part is for checking for SW3 input. If SW3 and SW4 are detected in
this stage it will go to the first part. If SW1 is detected in this stage it will trigger
alarm. If it detects SW2 it will go to this part again. The design of this state is
show below.
Figure 4: State3
STATE3
SW3,4
Delay STATE1 flowchart
LD5 on LD5 off
LD6 off LD6 on

In subroutine should contain the alarm function, delay function and SW4
function because these three functions are used many times in this task and it
will reduce program memory usage as well. The delay subroutine is use to
generate the delay for controller. This function is already provided in include file.
The alarm function will be called if any child move backward and it will trigger
LD1. The design of this function is show below.
SW1,2,3

Clear all LD1 on Delay LD1 off Delay SW4 Go to


LED SW4
function

Figure 5: Alarm function flowchart


The SW4 function is created for reset the board and go to first state including
stop the alarm function. The design of this function is show below.

Clear all LD6 on Go to Figure 6: SW4


LED Main function flowchart
loop
Achieved Functionality
After testing the program, all requirements are achieved. The program was tests
by pressing the sequence of pushbutton in order Switch1, Switch2 and then
Switch3. If any button were not press in this order it will triggered alarm but the
Switch1 and Switch2 can be place twice if it still in the same stage. Led5 and
Led6 were turn on and off correctly when the switch was pressed. Led1 was
blinking if any error occurs. Switch4 was able to reset the board in any state.
The size of the code is state in the figure below.

Figure 7: Memory usage of this program

Task2_B Generating the delay of 1ms using TMR0


From previous task, the delay that used in the program is already provided in
include file. In this task, the program must use TMR0 to generate precise 1 ms
delay instead of the program provided. In order to do that the programmer must
choose which prescale are going to use. There are two possible for prescale to
generate exactly 1ms delay. First one is 1:4 and second one is 1:8, these two
functions have to put in option register which have a different order of number.
In this program, it uses prescale of 1:8 which have to set the register to
00000010.Timer 0 have 1Mhz so it has to count 125 times with prescale of 1:8
to generate 1 ms delay which start counting from 130. But in simulation by
using stopwatch to measure it was not precisely 1ms. The values of “133” create
precisely 1ms.The relevant code is shown below.

ISR retfie
Delay movlw D'133' ;Start counting from 133 to 255
bcf INTCON,TMR0IE ;Clear TMR0IE
bcf INTCON,TMR0IF ;Clear TMR0IF
movwf TMR0

Loop btfss INTCON,TMR0IF ; check for TMR0 flag is set


goto Loop
return

Main nop
include AK_INIT.inc
banksel OPTION_REG ; select bank1
movlw B'00000010' ; use prescale of 1:8
movwf OPTION_REG ; move w to OPTION_REG
banksel TMR0 ; select bank0
Task2_C Setting LD6 on when a TMR0 interrupt occurs
The objective of this task is to use Timer 0 interrupt and make Led 6 on if
interrupt occurs. Firstly the program must enable global interrupt and TMR0
interrupt. The binary number 10100000 has to move in to INTCON register. The relevant
code is shown below.

ISR bcf INTCON,TMR0IF ; clear TMR0 flag


bsf LEDs,LD6 ;Turn led6 on
retfie
Main nop
Banksel OPTION_REG ; goto bank1
movlw B'00000010' ; use prescale of 1:8
movwf OPTION_REG ; move w to OPTION_REG
banksel TMR0 ; goto bank0

MLoop nop
movlw B'10100000' ; enable global interupt,timer0 interrupt flag
movwf INTCON

Task2_D Conversion into embedded C


The objective of this task is to convert the code from task 2_A into embedded C.
The design approach will be the same as task 2_A but the command is change in
to C language. The relevant code is shown below.
while (1) {
if (SWs == 0b00000001) //check for SW1
{
LEDs = 0b00010000; //if sw1 pressed then turn on only led 5
DelWds (3); //delay 3 ms
while(1){
if (SWs == 0b00000010) //check for SW2
{
DelWds (3); //delay 3ms
while(1)
{
if (SWs == 0b00000100) //check for SW3
{
LEDs = 0b00100000; //turn on only led6
break;
}
else if (SWs == 0b00001000) //check for SW4
{
DelWds (3); //delay 3ms
LEDs = 0b00100000; //turn on only led6
break;
}
else if (SWs == 0b00000001) //check for SW1
{
DelWds (3); //delay 3ms
do
{
LEDs = 0b00000001; //turn led1 on
DelWds (3); //delay 3ms
LEDs = 0b00000000; //turn off led
DelWds (3); //delay 3ms
} while (SWs != 0b00001000); //check for sw4
LEDs = 0b00100000; //turn on only led6
break;
}
.
.
.
.
.

}
break;
}
else if (SWs == 0b00001000) //check SW4
{
DelWds (3); //delay
LEDs = 0b00100000; //turn on only led6
break;
}
}
}
}

Question: Why you may want to use this delay program instead of the program
provided?
Because TMR0 use internal clock oscillator of 4 MHz which make it more precise
than use the delay by running the loop in the program.

Comment on testing of task 1


This assignment is about sending a Morse code. On task 1_A, all of function was
achieved but on task 1_D which used the same function and convert from C
language is not working in the same way as task 1_A. However there are some
misunderstand in this task as the programmer said he not understands the
whole question. It suppose to send 1 message if press SW2, 2messages if press
SW3 and send three messages if both SW are pressed but from his code the
program will send two message either which button were pressed. Task 1_B was
also checked and it can use CCP and TMR1 to turn led3 on in 0.4 second after
program start. Task 1_C was also working properly. Led6 is turning on when
CCP interrupt occur.

Suggestion
The specification of the programming is not totally clear in task2_A. In task 2_A
it said “if the user moved backward for any reason the alarm LD1 is triggered”
but if in this process the user are skip the procedure what should the output look
like. For example if the child already enter the flume and SW1 was pressed then
the user are press the SW3 which mean the child are already out of the flume
and SW2 was not press. In task 2_B, it has state that the delay must precise 1
ms delay. The only way to test that is to use stopwatch in MPLAB program
because the human eyes cannot see the led blinking with a delay of 1ms.
2009
-

Author:
4074719

H63 ECH – Task 3 Volume Controller

[THE UNIVERSITY OF
NOTTINGHAM EEE SCHOOL]
Task A

The approach used in this task was to initialize by setting both the volume levels – the dance floor and the
headphone to level 4. Then, by the help of a never-ending super-loop – the standby state is displayed in the
LEDs in the binary form where LD1…LD3 represent the headphone volume level and LD4…LD6 represent the
dance floor’s volume level.

Then the switches are read with a State Diagram


debouncing function to prevent the
compiler from mistaking a single switch-
press as multiple presses. According to
the switch pressed – the corresponding
subroutine is called where the
corresponding action takes place. Like, if
SW4 is pressed, both the volume levels
will be set to level 4. When, SW1 is
pressed, the headphone’s volume level
is copied into the dance floor’s volume
level. When the incrementing (SW3) or
the decrementing (SW2) switches are
pressed, the corresponding subroutine
checks if the volume levels will be in
range (i.e., 0…7) after the execution
before actually incrementing or
decrementing. A delay of 0.2 seconds is
used to ensure smooth switch presses Flowchart
and proper running of the DJ system. In
this coursework, complete functionality
has been achieved so that no glitches
whatsoever occur. All the switches do
their respective actions and the LEDs
instantaneously display the
corresponding result.
Task B

This task involves controlling the brightness of LD3 using PIC peripherals TMR2 and CCP (PWM) with the
PWM pulse wave of duty cycle 50%.

The PWM frequency below 1kHz chosen for this task is 625Hz.
So, PWM period = 1/625 = 0.0016s
We know from the datasheet that,

PWM period = [PR2 + 1].4.(Prescale value).Tosc


So, 0.0016 = [PR2 + 1]. 4 . 16 . (0.25 x 10-6)
Therefore, PR2 = 99 (since we took prescale to be 16)

Also, its given that the duty cycle is 50%.


So, from the duty cycle equation, we have:

PWM Duty cycle = [CCPR1L,CCP1CON<5:4>] (Prescale value).Tosc


So, 0.0016 x 50% = [CCPR1L,CCP1CON<5:4>] 16 . (0.25 x 10-6)
Therefore, [CCPR1L,CCP1CON<5:4>] = 200 (since we took prescale to be 16)

Relevant pieces of code for this task are explained with comments:

; 1. writing to the CCPR1L register


movlw B'00110010' ;writing 1st 8 MSBs of the 10-bit resolution PWM
movwf CCPR1L ;duty cycle to the 8-bit CCPR1L register

; 2. setting the PWM period by writing to the PR2 register


movlw D'99' ;moving the literal value 99 to w
movwf PR2 ;and writing it to the 8-bit PR2 register

; 3. disabling interrupts and clearing flags


bcf PIE1,CCP1IE ;disables the CCP1 interrupt
bcf PIE1,TMR2IE ;disables the TMR2 to PR2 match interrupt
bcf PIR1,TMR2IF ;clear TMR2 to PR2 match interrupt flag (after
overflow)

; 4. configuring CCP1 pin as output


bcf TRISB,LD3 ;configures the CCP1 pin as output
;since CCP1 pin is multiplexed
;with the PORTB data latch

; 5. setting the PWM duty cycle


movlw B'00001100' ;bits 7-6: unimplemented
movwf CCP1CON ;bits 5-4: LSBs of PWM duty cycle
;bits 3-0: 11xx is CCP1 PWM mode
;PWM duty cycle: CCPR1L:CCP1CON<5:4>
; => B'0011001000'
; => D'200'

; 6. initializing and setting the Timer2 ON


movlw B'00000110' ;bit 8: unimplemented
movwf T2CON ;bits 7-3: 4-bit postscaler - set to 0 as its
irrelevant
;bit 2: TMR2 set=on or clear=off bit
;bits 1-0: 2-bit prescaler - bits 10 represent 1:16
Task C
In the main program, we enable Timer2 interrupt, the global and peripheral interrupts so that priority of
interrupt calling may not affect our task. Finally, we write to the PR2 register and also the T2CON to switch the
timer ON.

Main program:

bsf PIE1,TMR2IE ;enables the TMR2 to PR2 match interrupt

movlw D'99' ;writes the value 99 to the PR2 register


movwf PR2 ;for this task - any value should be fine

movlw B'00000110' ;sets the prescaler to 1:16 (bits 1-0:10)


movwf T2CON ;and switches on the timer (bit 2:set)

bsf INTCON,PEIE ;enables peripheral interrupt bit

bsf INTCON,GIE ;enables global interrupt bit

The interrupt service routine is called when the Timer2 overflows which is when TMR2 becomes equal to PR2.
Then, TMR2 is reset to 0 and the processor is interrupted and transferred to the start of the interrupt service
routine.

In the interrupt routine, we clear the interrupt flag so that next time an interrupt may need to be called – that it
will not be a problem. Then, as the task requires, LD6 is lit up.

Interrupt Service Routine:

ISR

bcf PIR1,TMR2IF ;clears the TMR2 to PR2 match interrupt flag bit

bsf PORTB,LD6 ;sets the LD6 bit on

retfie ;returns to where the processor was interrupted


Task D

Embedded C Code:

#include <htc.h>
#include "inclC.c"
#define LEDs PORTB

main ()
{
unsigned char VOL_D;
unsigned char VOL_H;
// configure pins
ADCON1 = 0b00000110; // disable ADC inputs
PORTB = 0;
TRISB = 0b11000000; // configure RB5..RB0 for output

VOL_D = VOL_H = 4; // setting both dance floor and headphone to level 4

// superloop
while (1)
{
unsigned char temp = VOL_D;

temp = temp << 3;


LEDs = temp | VOL_H;
__delay_ms(20);

// if-else structure - to choose which state


if (PORTA == 0b00000001) // if SW1 is pressed or bit RA0 is high
{
VOL_D = VOL_H; // copies the vol_h to vol_d
}
else if (PORTA == 0b00000010) // if SW2 is pressed or bit RA1 is high
{
while(PORTA == 0b00000010){}
if (VOL_H > 0) VOL_H--; // decr level of VOL_H, skip if zero
}

else if (PORTA == 0b00000100) // if SW3 is pressed


{
while(PORTA == 0b00000100){}
if (VOL_H < 7) VOL_H++; //incr level - VOL_H,skip if 7
}

else if (PORTA == 0b00001000) // if SW4 is pressed


{
VOL_D = VOL_H = 4; // resets both levels to 4
}
} // end of Main while loop or superloop

} // end of Main function

The while-loop in the increment and decrement if conditions maybe repetitions of checking for which switch
has been pressed. However, they are not redundant because these while-loops effectively prevent the
compiler mistaking a single switch-press as multiple presses. Another approach to solving this issue could be
adding a sufficient delay of about 0.3 seconds at the beginning of the superloop and using the ReadSw()
function – but in the Hi-Tech Compiler, the former approach (of using the while-loops) works both in the
Debugger & Programmer modes and is 7 instructions lesser than the latter approach which works only in the
Programmer mode.
Another approach to displaying LEDs (but more instructions) is as follows:
unsigned char temp = VOL_D; // store dancefloor volume in temp
unsigned char sum = 0; // initialize sum to zero
sum = VOL_H; // add headphone volume to sum
sum += (temp%2)*8; // add 8 if bit 0 of dancefloor volume is 1
temp /= 2;
sum += (temp%2)*16; // add 16 if bit 1 of dancefloor volume is 1
temp /= 2;
sum += (temp%2)*32; // add 32 if bit 2 of dancefloor volume is 1
LEDs = sum; // write the value of sum to PORTB

Comments on testing Task 2:

I thought the logic in the programming structure of 4085517’s Task 2 was well-thought.

I found the question in task A slightly ambiguous. If the alarm is supposed to go off only when switches ‘121’
are pressed, then 4085517’s code is complete. But, if alarm is to be called on other occasions like for
example, on switches ‘132’ & ‘122’ as it is a flume – then the code is incomplete.

In task C, all flags are not cleared and global interrupts are not declared. Although the code runs fine and LD6
lights up, this code if run over and over again would be potentially hazardous.

Answer to the coursework question:

The LED brightness might differ from 50% because of many factors.

Excessive use of computing time (due to running other instructions in the program code) and a poor PWM
resolution can cause glitches at the low frequencies that are being used.

Also, since the duty cycle for the PIC microcontroller is the number of basic oscillator cycles for the output to
remain high and not the generic duty cycle measured as a percentage – the duty cycle is related only to the
master clock and not to the period of the PWM signal. This may prevent us from getting an accurate duty
cycle.

Suggestions:

An additional task for this coursework could be an extension to the existing simple and small PWM and
interrupt tasks. The task could be to create various LED dimmer effect of different frequencies on the different
LEDs.

Another additional task could be to receive and transmit messages between two PICs using the switches as
information bits and the LEDs to display the incoming and outgoing information in binary on three LEDs each.

It would have been really helpful to understand if we were to build the PIC board as the datasheet would
become more clear and functions of various pins, resistors and connections would become known.
2009
-

Author:
4072770

H63 ECH – Task 4 Binary Calculator

[THE UNIVERSITY OF
NOTTINGHAM EEE SCHOOL]
ID : 4072700 Group : 11 Assignment : 4

Task A
A truth table was drawn for all possible input values for A & B:

A1 A0 B1 B0 3*A+[B/2] R3 R2 R1 R0
0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 1 0 1 0 0 0 1
0 0 1 1 1 0 0 0 1
0 1 0 0 3 0 0 1 1
0 1 0 1 3 0 0 1 1
0 1 1 0 4 0 1 0 0
0 1 1 1 4 0 1 0 0
1 0 0 0 6 0 1 1 0
1 0 0 1 6 0 1 1 0
1 0 1 0 7 0 1 1 1
1 0 1 1 7 0 1 1 1
1 1 0 0 9 1 0 0 1
1 1 0 1 9 1 0 0 1
1 1 1 0 10 1 0 1 0
1 1 1 1 10 1 0 1 0

these result values were used as the return values for the lookup table,

Start loop Store B

Copy to LD1-2
Read SW3-4
& set LD6 Wait for SW1
No to unset

SW1 set?
Combine A&B
and use lookup Show result
Yes
table
Store A
Yes Wait 1s
Wait for SW1
to unset
Calculate result Show result
Copy to LD1-2
Read SW3-4 & set LD6
Wait 1s
No
SW1 set? End loop
ID : 4072700 Group : 11 Assignment : 4

Task B

; SUBROUTINES
;******************************************************
ISR retfie

;******************************************************
; end of your subroutines

; INITIALISATION
;******************************************************
; set prescaler for wdt
BANKSEL OPTION_REG
movlw b'11111111' ; sets wdt prescaler for a 2s delay
movwf OPTION_REG
BANKSEL SWs

;******************************************************
; end of your initialisation

; MAIN code
;******************************************************
movlw b'00001111' ; switch mask, SW5 seems to come on sometimes when
pressing SW4
andwf SWs, W
btfss STATUS, Z ; check whether a switch has been pressed
clrwdt ; if a switch has been pressed, clear the timer
to prevent a reset
movwf LEDs ; Show the switches pressed on the LEDs

;******************************************************
; end of main code
ID : 4072700 Group : 11 Assignment : 4

Task C

For this task the register LEDstat is used to keep LD6 on as the status will
change when WDT is cleared.

; SUBROUTINES
;******************************************************
ISR retfie

;******************************************************
; end of subroutines

; INITIALISATION
;******************************************************
; Sets LD6 if reset by watchdog timer
btfss STATUS, 4
movlw B'00100000'
movwf LEDstat

; set prescaler for wdt


BANKSEL OPTION_REG
movlw b'11111111' ; sets wdt prescaler for a 2s delay
movwf OPTION_REG
BANKSEL SWs
;******************************************************
; end of initialisation

; MAIN code
;******************************************************
movlw b'00001111' ; switch mask, SW5 seems to come on sometimes when
pressing SW4
andwf SWs, W
btfss STATUS, Z ; check whether a switch has been pressed
clrwdt ; if a switch has been pressed, clear the timer
to prevent a reset
iorwf LEDstat,W ; sets LD6 if PIC was reset by watdog timer
movwf LEDs ; Show the switches pressed on the LEDs

;******************************************************
; end of main code
ID : 4072700 Group : 11 Assignment : 4

Task D

/* subroutine to avoid bouncing */


unsigned char ReadSw(void) {
unsigned char tmp;
tmp=0;
while (tmp != PORTA) {
tmp = PORTA;
__delay_ms(1);
}
return tmp & 0b00001111;
}

/* delay for n 10ths of a second */


void delay_ds(unsigned char n){
unsigned char ctr;
for (ctr=1;ctr<n;ctr++)
__delay_ms(100); /* up to 197 */
}

unsigned char lookup[] = {0, 0, 1, 1, 3, 3, 4, 4, 6, 6, 7, 7, 9, 9, 10, 10};

main () {
/* configure pins */
ADCON1 = 0b00000110;
TRISB = 0b11000000;

/* LEDs on for 1 s */
PORTB = 0b00111111;
delay_ds(10);

/* copy switches to LEDs */


while (1){
char opA, opB, tmp = ReadSw(); // read Switches and store in tmp
while (!(tmp&1)){ // loop until SW1 is pressed
// read Switches and store in tmp, shift right 2 bits and store in
opA, set bit<5> and write to PORTB
PORTB = 0b00100000 | (opA = (tmp=ReadSw()) >> 2);
}
while (ReadSw()&1); // loop until SW1 is let go
tmp=ReadSw(); // read Switches and store in tmp
while (!(tmp&1)){ // loop until SW1 is pressed
// read Switches and store in tmp, shift right 2 bits and store in
opB, set bit<5> and write to PORTB
PORTB = 0b00010000 | (opB = (tmp=ReadSw()) >> 2);
}
while (ReadSw()&1); // loop until SW1 is let go

// shift A left 2 bits and append B to get result from lookup table
PORTB = lookup[(opA<<2) + opB];
delay_ds(10); // for 1 second
ID : 4072700 Group : 11 Assignment : 4

PORTB=0; // show nothing


delay_ds(5); // for 0.5seconds

result = (opA*3) + (opB >> 1); // perform calculation


PORTB = result; // show result
delay_ds(10); // for 1 second
}
}

Compare two ways of implementing the calculator in terms of


memory required and speed of execution. What would change in
your analysis if 4bit operands were used ?

The calculation method uses far less instructions(7) than the lookup
method(25) for this, as it is a simple calculation. If 4 bit operands were
used, the size of the lookup table alone would increase from 17 instructions
to 257 instructions, the calculation method however, would not gain in size,
the current code I am using is capable of working with 4bit operands.

Suggestions / Mistakes

Description states that task C is an interrupt for all assignments but it is not
for assignment 4.
Completion of the developments

Task Assignment
1 2 3 4
A + + + +
B + + + +
C + + + +
D ? + + +

Please insert in the table the following symbols as applicable:


+ the task fully completed and tested as such
? there is a disagreement between the developer and the tester
a task attempted but was not developed to completion, not tested
- task was not attempted

Size of the developed codes


Debug mode:
Task Assignment
1 2 3 4
A 168 77 82 112
B 61 57 59 54
C 74 53 55 58
D 281 178 112 294

Release mode:
Task Assignment
1 2 3 4
A 185 94 99 129
B 78 74 76 71
C 91 70 72 75
D 281 178 112 294

To determine the number for the table, please select “Memory usage gauge”
in View menu of MPLAB at the end of the development. The gauge will show
how many instructions and registers are used by your program. The template
itself requires 48 instructions and 8 registers to operate. Therefore 48 was put
as an example – this is the minimal size your code could be as it is not allowed
to modify my template. You will need to put in the table your data, and your
codes will be assessed on their size in comparison to the codes developed by
people from the other groups for the same assignment. The less size of the
code, the higher the mark.

You might also like