Home | Notes | Projects > ARM-Assembly Vending Machine
An ARM assembly program to simulate a soft drink vending machine using Raspberry Pi board, buttons and LEDs
To get familiar with ARMv7 assembly language. (Syntax, addressing modes, etc.)
To get familiar with generic ARM assembly program structure.
To get familiar with LED interfacing. (Polling)
To get familiar with button interfacing. (Polling)
To understand the necessity of "Input debouncing time".
Raspberry Pi 3 Model B V1.2
OS: Raspbian CNU/Linux 11 (bullseye) (Kernel version: 5.15.61-v7+)

The machine will dispense, upon receipt of the correct amount of change of 55 cents, a choice of Coke, Sprite, Dr. Pepper, or Coke Zero. Your software will perform the following:
Display a welcome message and instructions.
Accept money inputs of nickels (N), dimes (D), quarters (Q), and one-dollar bills (B).
Reject any invalid money inputs.
Set the initial inventory of drinks to two of each kind.
Once the money input is 55 cents or greater prompt the user on what soft drink they want. (C) Coke, (S) Sprite, (P) Dr. Pepper, or (Z) Coke Zero
Verify with the user what drink they selected and allow them to cancel that selection and be prompted for another drink selection.
Reject any invalid soft drink selections.
There should also be an option to cancel the transaction and return any money deposited by the user.
If the user selects an out of inventory drink prompt them to make another selection.
Dispense the selected drink and any change due.
Drink machine will shut down when the entire inventory reaches zero.
Assume there is no limit on the amount of change the drink machine contains.
Make provisions for a secret code that when entered will display the current inventory of drinks. For grading purposes identify the secret code and when it can be entered in the welcome message.
Red LED
Power ON
This LED will come on for 5 seconds when the program starts running then turn off.
Coke being dispensed
This LED will flash 3 times (1 second on, 1 second off) then stay on for 5 seconds then turn off to signify the drink has been dispensed.
Power OFF
The LED will come on for 5 seconds when the drink inventory is depleted then turn off. The program will then be terminated.
Yellow LED
Sprite being dispensed
This LED will flash 3 times (1 second on, 1 second off) then stay on for 5 seconds then turn off to signify the drink has been dispensed.
Green LED
Dr. Pepper being dispensed
This LED will flash 3 times (1 second on, 1 second off) then stay on for 5 seconds then turn off to signify the drink has been dispensed.
Blue LED
Coke Zero being dispensed– This LED will flash 3 times (1 second on, 1 second off) then stay on for 5 seconds then turn off to signify the drink has been dispensed.
Red Button
Dispense a Coke
Yellow Button
Dispense a Sprite
Green Button
Dispense a Dr. Pepper
Blue Button
Dispense a Coke Zero
xxxxxxxxxx7041/*****************************************************************************************2 * File Name : soft_drink_machine.s3 * Description : ARM assembly program to simulate a soft drink machine using RaspberryPi4 * board, buttons and LEDs5 * Author : Kyungjae Lee6 * File Created : 10/24/20227 *----------------------------------------------------------------------------------------8 *9 * Commands to assemble, link, run program:10 * as -o <filename.o> <filename.s>11 * gcc -o <filename> <filename.o> -lwiringPi12 * sudo ./<filename>13 *14 * Commands to debug program:15 * as -g -o <filename.o> <filename.s> @ -g option creates debug symbols16 * gcc -g -o <filename> <filename.o> -lwiringPi17 * @ -g option creates debug symbols18 * @ (without this option, source code and the line19 * @ number won't be visible on your debug window)20 * gdb ./<filename> @ cannot use debugger with sudo21 * layout next22 *23 * How to download and build wiringPi?24 * From the directory of your preference run the following commands:25 * 1. git clone https://github.com/WiringPi/WiringPi.git26 * 2. cd WiringPi/27 * 3. ./build28 * Then the wiringPi library will be ready to be linked during compilation.29 ****************************************************************************************/30 31.equ READERROR, 0 @ Used to check for scanf read error.32.equ DRINK_COUNTER, 8 @ Total number of soft drinks in the inventory.33.equ OUTPUT, 1 @ Used to set the selected GPIO pins to output only.34.equ DELAYMS_1000, 1000 @ Delay for one second.35.equ DELAYMS_5000, 5000 @ Delay for five seconds.36.equ BLINK_COUNTER, 3 @ Used to count the number of times LED blinks.37
38@ Define the following from wiringPi.h header39@ Instead of using '.equ', following syntax also works for defining constants40
41OUTPUT = 142INPUT = 043
44PUD_UP = 245PUD_DOWN = 146
47LOW = 048HIGH = 149
50@ Register usage:51@52@ - r1 : (button) Used to keep track of the red button press status53@ - r2 : (button) Used to keep track of the yellow button press status54@ - r4 : Used to store the change55@ - r5 : Used to store the address of 'arrInventory'56@ (button) Used to keep track of the green button press status57@ - r6 : Used to store the offset from the address of 'arrInventory'58@ - r7 : Used to store the address of an element of 'arrInventory'59@ (button) Used to keep track of the blue button press status60@ - r8 : Used to store the address of the name of the selected drink61@ - r9 : Used as the drink counter62@ - r10 : Used to store the LED pin number corresponding to the dispensed soft drink.63@ - Coke (pin2) : Red LED64@ - Sprite (pin3) : Yellow LED65@ - Dr.Pepper (pin4) : Green LED66@ - Coke Zero (pin5) : Blue LED67@ - r11 : Used as the LED blink counter68
69@ LED mapping70@ 71@ - pin2: blue72@ - pin3: green73@ - pin4: yello74@ - pin5: red75
76.text77
78.global main79
80@-----------------------------------------------------------------------------------------81main:82@-----------------------------------------------------------------------------------------83
84@ Setup r9 so it counts the number of soft drinks left in the inventory. The program will85@ terminate when the inventory becomes empty (r9 = 0)86
87 mov r9, #DRINK_COUNTER 88
89@ Check the setup of the GPIO to make sure it is working right.90@ To use the wiringPiSetup function just call it.91@ Upon return, r0 contains the pass(0)/fail(-1) code.92 93 bl wiringPiSetup94 mov r1, #-195 cmp r0, r196 bne init @ Everything is OK so continue with code.97 ldr r0, =str14 @ Load wiringPiSetup fail message to r0 for printf call.98 bl printf99 b exit @ There is a problem with the GPIO exit code.100
101@-----------------------------------------------------------------------------------------102init:103@-----------------------------------------------------------------------------------------104
105@ Set four GPIO pins to output.106
107 @ Set the pin2 to output mode108 ldr r0, =pin2109 ldr r0, [r0]110 mov r1, #OUTPUT111 bl pinMode112
113 @ Set the pin3 to output mode114 ldr r0, =pin3115 ldr r0, [r0]116 mov r1, #OUTPUT117 bl pinMode118
119 @ Set the pin4 to output mode120 ldr r0, =pin4121 ldr r0, [r0]122 mov r1, #OUTPUT123 bl pinMode124
125 @ Set the pin5 to output mode126 ldr r0, =pin5127 ldr r0, [r0]128 mov r1, #OUTPUT129 bl pinMode130
131 @ Pin2, 3, 4, 5 are now setup for output.132
133@ Setup four input buttons.134
135 @ Set the mode to input - Blue button136 ldr r0, =buttonBlue137 ldr r0, [r0]138 mov r1, #INPUT139 bl pinMode140
141 @ Set the mode to input - Green button142 ldr r0, =buttonGreen143 ldr r0, [r0]144 mov r1, #INPUT145 bl pinMode146
147 @ Set the mode to input - Yellow button148 ldr r0, =buttonYellow149 ldr r0, [r0]150 mov r1, #INPUT151 bl pinMode152
153 @ Set the mode to input - Red button154 ldr r0, =buttonRed 155 ldr r0, [r0]156 mov r1, #INPUT157 bl pinMode158
159@ Set the buttons for pull-up and it is 0 when pressed.160@ - pullUpDnControl(buttonPin, PUD_UP)161@ - digitalRead(buttonPin) == LOW button pressed162
163 ldr r0, =buttonBlue164 ldr r0, [r0]165 mov r1, #PUD_UP166 bl pullUpDnControl167
168 ldr r0, =buttonGreen169 ldr r0, [r0]170 mov r1, #PUD_UP171 bl pullUpDnControl172
173 ldr r0, =buttonYellow174 ldr r0, [r0]175 mov r1, #PUD_UP176 bl pullUpDnControl177
178 ldr r0, =buttonRed179 ldr r0, [r0]180 mov r1, #PUD_UP181 bl pullUpDnControl182
183@ At power on, turn on red LED for 5 seconds and then turn it off.184
185 bl ledAtPowerOnOff186
187@-----------------------------------------------------------------------------------------188inventoryCheck:189@-----------------------------------------------------------------------------------------190
191@ Display a welcome message and instructions.192
193 ldr r0, =str0 @ Load welcome message to r0 for printf call.194 bl printf @ Print it to the screen.195
196 mov r4, #0 @ Initialize r4 (will be used to keep user input change)197
198@-----------------------------------------------------------------------------------------199loop:200@-----------------------------------------------------------------------------------------201
202 cmp r4, #55203 bge drinkSelection204
205 ldr r0, =str1 @ Load instruction message to r0 for printf call.206 bl printf @ Print it to the screen.207
208
209@ Accept money inputs of nickels (N), dimes (D), quarters (Q), and one-dollar bills (B).210
211 ldr r0, =strInPattern @ Load r0 with the addr of char input pattern for scnaf call.212 ldr r1, =charInput @ Load r1 with the addr of the memory location where the user213 @ input will be stored.214 bl scanf215
216@ Check the validity of the user input. Reject any invalid money inputs.217
218 cmp r0, #READERROR @ Check for a read error.219 beq invalidInput220 ldr r1, =charInput @ Reload r1 since it gets wiped out after scanf call.221 ldrb r1, [r1] @ Load r1 with the user input so it can be used later.222
223 cmp r1, #'N'224 addeq r4, #5225 moveq r1, r4226 ldreq r0, =str11 @ Load running total change message to r0 for printf call.227 bleq printf @ Print it to the screen.228 beq loop229
230 cmp r1, #'D'231 addeq r4, #10232 moveq r1, r4233 ldreq r0, =str11 @ Load running total change message to r0 for printf call.234 bleq printf @ Print it to the screen.235 beq loop236
237 cmp r1, #'Q'238 addeq r4, #25239 moveq r1, r4240 ldreq r0, =str11 @ Load running total change message to r0 for printf call.241 bleq printf @ Print it to the screen.242 beq loop243
244 cmp r1, #'B'245 addeq r4, #100246 moveq r1, r4247 ldreq r0, =str11 @ Load running total change message to r0 for printf call.248 bleq printf @ Print it to the screen.249 beq loop250
251 cmp r1, #'K' @ Secret code252 beq secretCode253
254 b invalidInput255
256@-----------------------------------------------------------------------------------------257drinkSelection:258@-----------------------------------------------------------------------------------------259
260 ldr r0, =str3 @ Load drink selection message to r0 for printf call.261 bl printf @ Print it to the screen.262
263@ Accept drink selection by button press.264@ - Coke (Red), Sprite (Yellow), Dr.Pepper (Green), Coke Zero (Blue)265
266@ Set the registers to debounce switches and handle buttons held down.267
268 mov r1, #0xFF269 mov r2, #0xFF270 mov r5, #0xFF271 mov r7, #0xFF272
273buttonLoop:274
275@ Delay a few milliseconds to help debounce the switches.276
277 ldr r0, =delayMs250278 ldr r0, [r0]279 bl delay280
281readRED:282
283@ Read the value of the red button. If it is HIGH (i.e., not pressed) read the next button284@ and set the previous reading value to HIGH. 285@ Otherwise, the current value is LOW (pressed). If it was LOW and its last recorded286@ status was LOW, then do not record this as a new pressing. 287@ If it was HIGH the last time and LOW now, then record the button has been pressed.288 289 ldr r0, =buttonRed290 ldr r0, [r0]291 bl digitalRead292 cmp r0, #HIGH @ If the button is HIGH, read next button293 moveq r1, r0 @ Set last time read value to HIGH294 beq readYellow295
296 @ The button value is LOW.297 @ If it was LOW the last time it is still down.298 cmp r1, #LOW @ Was the last time it was called also down?299 beq readYellow @ Button is still down. Read next button value.300
301 mov r1, r0 @ This is a new button press.302 b selectCoke @ Branch to handle the red button press.303
304readYellow:305 306 ldr r0, =buttonYellow307 ldr r0, [r0]308 bl digitalRead309 cmp r0, #HIGH310 moveq r2, r0311 beq readGreen312
313 cmp r2, #LOW314 beq readGreen315
316 mov r2, r0317 b selectSprite318
319readGreen:320 321 ldr r0, =buttonGreen322 ldr r0, [r0]323 bl digitalRead324 cmp r0, #HIGH325 moveq r5, r0326 beq readBlue327
328 cmp r5, #LOW329 beq readBlue330
331 mov r5, r0332 b selectDrPepper333
334readBlue:335 336 ldr r0, =buttonBlue337 ldr r0, [r0]338 bl digitalRead339 cmp r0, #HIGH340 moveq r7, r0341 beq buttonLoop342
343 cmp r7, #LOW344 beq buttonLoop345
346 mov r7, r0347 b selectCokeZero348
349selectCoke:350
351 mov r6, #0352 ldr r8, =strCoke353 ldr r10, =pin5 @ When 'Coke' is confirmed, get LED5 ready354 b confirmSelection355
356selectSprite:357
358 mov r6, #4359 ldr r8, =strSprite360 ldr r10, =pin4 @ When 'Sprite' is confirmed, get LED4 ready361 b confirmSelection362
363selectDrPepper:364
365 mov r6, #8366 ldr r8, =strDrPepper367 ldr r10, =pin3 @ When 'Dr.Pepper' is confirmed, get LED3 ready368 b confirmSelection369
370selectCokeZero:371
372 mov r6, #12373 ldr r8, =strCokeZero374 ldr r10, =pin2 @ When 'Coke Zero' is confirmed, get LED2 ready375 b confirmSelection376
377@-----------------------------------------------------------------------------------------378confirmSelection:379@-----------------------------------------------------------------------------------------380
381 ldr r5, =arrInventory382 ldr r7, [r5, r6]383 cmp r7, #0384 beq outOfInventory385
386 mov r1, r8 @ Load r8 with the address of the selected drink name.387 ldr r0, =str8 @ Load confirmation message to r0 for printf call.388 bl printf @ Print it to the screen.389
390@ Accept user confirmation input (Y or N)391
392 ldr r0, =strInPattern @ Load r0 with the addr of char input pattern for scnaf call.393 ldr r1, =charInput @ Load r1 with the addr of the memory location where the user394 @ input will be stored.395 bl scanf396
397@ Check the validity of the user input. Reject any invalid money inputs.398
399 cmp r0, #READERROR @ Check for a read error.400 beq invalidInput401 ldr r1, =charInput @ Reload r1 since it gets wiped out after scanf call.402 ldrb r1, [r1] @ Load r1 with the user input so it can be used later.403
404 cmp r1, #'Y'405 bne drinkSelection406 sub r7, r7, #1407 str r7, [r5, r6] @ Store the updated inventory value back to the array.408
409 sub r4, r4, #55410
411 mov r1, r8 @ Load r8 with the address of the selected drink name.412 mov r2, r4 @ Load r2 with the net change.413 ldr r0, =str9 @ Load out of confirmation message to r0 for printf call.414 bl printf @ Print it to the screen.415
416 bl ledAtDispense @ Corresponding led signify the confirmed dispense417 418 sub r9, r9, #1 @ Decrement the total number of soft drinks in the inventory.419 cmp r9, #0 @ Check if inventory is empty420 bne inventoryCheck421
422 b exit423
424@-----------------------------------------------------------------------------------------425outOfInventory:426@-----------------------------------------------------------------------------------------427
428 mov r1, r8429 ldr r0, =str7 @ Load out of inventory message to r0 for printf call.430 bl printf @ Print it to the screen.431 432 b drinkSelection433 434@-----------------------------------------------------------------------------------------435secretCode:436@-----------------------------------------------------------------------------------------437
438 ldr r5, =arrInventory439
440 ldr r1, =strCoke441 ldr r2, [r5]442 ldr r0, =str13 @ Load inventory status for Coke to r0 for printf call.443 bl printf @ Print it to the screen.444
445 ldr r1, =strSprite446 ldr r2, [r5, #4]447 ldr r0, =str13 @ Load inventory status for Coke to r0 for printf call.448 bl printf @ Print it to the screen.449
450 ldr r1, =strDrPepper451 ldr r2, [r5, #8]452 ldr r0, =str13 @ Load inventory status for Coke to r0 for printf call.453 bl printf @ Print it to the screen.454 455 ldr r1, =strCokeZero456 ldr r2, [r5, #12]457 ldr r0, =str13 @ Load inventory status for Coke to r0 for printf call.458 bl printf @ Print it to the screen.459
460 b inventoryCheck461
462@-----------------------------------------------------------------------------------------463invalidInput:464@-----------------------------------------------------------------------------------------465
466 ldr r0, =readlinePattern467 ldr r1, =invalidDump @ Load r1 with the memory buffer's address.468 bl scanf @ Make the scanf call.469
470 ldr r0, =str6 @ Load r0 with the error message.471 bl printf @ Print the error message to the screen.472
473 b loop @ Branch back to loop so that user can re-enter the values.474
475@-----------------------------------------------------------------------------------------476ledAtPowerOnOff:477@-----------------------------------------------------------------------------------------478
479@ At power on/off, red LED turns on for 5 seconds and then turns off.480
481 push {lr} @ Store the address where this subroutine was called.482
483 @ Write a logic one to turn pin5 to on.484 ldr r0, =pin5485 ldr r0, [r0]486 mov r1, #1487 bl digitalWrite488
489 @ Run the delay (otherwise it blinks so fast that you will never see it!)490 @ To use the 'delay' function, r0 must contain the number of miliseconds to delay.491 ldr r0, =delayMs5000492 ldr r0, [r0]493 @ mov r0, #DELAYMS_5000494 bl delay495
496@ Turn off the LED497
498 @ Write a logic one to turn the corresponding pin (stored in r10) to off.499 ldr r0, =pin5500 ldr r0, [r0]501 mov r1, #0502 bl digitalWrite503
504 pop {pc} @ Force return back to where this subroutine was called.505
506@-----------------------------------------------------------------------------------------507ledAtDispense:508@-----------------------------------------------------------------------------------------509
510@ At dispense, red LED blinks for 3 seconds (1 sec on / 1 sec off) and then stays on for 5511@ seconds then turns off to signify the drink has been dispensed.512
513 push {lr} @ Store the address where this subroutine was called.514
515 mov r11, #BLINK_COUNTER @ Setup the blink counter (set to 3)516
517loopBlink:518
519 cmp r11, #0520 beq endLoopBlink521
522@ Turn on LED for 1 second523
524 @ Write a logic one to turn the corresponding pin (stored in r10) to on.525 ldr r0, [r10]526 mov r1, #1527 bl digitalWrite528
529 @ Run the delay (otherwise it blinks so fast that you will never see it!)530 @ To use the 'delay' function, r0 must contain the number of miliseconds to delay.531 mov r0, #DELAYMS_1000532 bl delay533
534@ Turn off LED for 1 second535
536 @ Write a logic one to turn the corresponding pin (stored in r10) to off.537 ldr r0, [r10]538 mov r1, #0539 bl digitalWrite540
541 mov r0, #DELAYMS_1000542 bl delay543
544 sub r11, #1545 b loopBlink546
547endLoopBlink:548
549@ Turn on LED for 5 second550
551 @ Write a logic one to turn the corresponding pin (stored in r10) to on.552 ldr r0, [r10]553 mov r1, #1554 bl digitalWrite555
556 @mov r0, #DELAYMS_5000557 ldr r0, =delayMs5000558 ldr r0, [r0]559 bl delay560 561@ Turn off LED 562
563 @ Write a logic one to turn the corresponding pin (stored in r10) to off.564 ldr r0, [r10]565 mov r1, #0566 bl digitalWrite567
568 pop {pc} @ Force return back to where this subroutine was called.569
570@-----------------------------------------------------------------------------------------571exit:572@-----------------------------------------------------------------------------------------573
574 ldr r0, =str12 @ Load r0 with the terminating message.575 bl printf @ Print the error message to the screen.576
577 bl ledAtPowerOnOff578
579@ Force the exit and return control to OS.580
581 mov r7, #1 @ SVC call to exit582 svc 0 @ Make the system call583
584
585.data586
587@ Strings588
589.balign 4 @ Force a word boundary590str0: .asciz "\nWelcome to Mr. Lee's soft drink vending machine.\nCost of Coke, Sprite, Dr. Pepper, and Coke Zero is 55 cents. (Secret code: K)\n\n"591
592.balign 4 @ Force a word boundary593str1: .asciz "Enter money nickel(N), dime(D), quarter(Q), and one dollar bill(B).\n"594
595.balign 4 @ Force a word boundary596str2: .asciz "Total is %d cents.\n\n"597
598.balign 4 @ Force a word boundary599str3: .asciz "Make selection:\n(Red) Coke, (Yellow) Sprite, (Green) Dr. Pepper, or (Blue) Coke Zero.\n"600
601.balign 4 @ Force a word boundary602str4: .asciz "Selection is %s. Is this OK? (Y or N)."603
604.balign 4 @ Force a word boundary605str5: .asciz "A %s has been dispensed with 0 cents change."606
607.balign 4 @ Force a word boundary608str6: .asciz "ERROR: Invalid input. Please try again!\n\n"609
610.balign 4 @ Force a word boundary611str7: .asciz "%s is out of inventory. Try different one!\n\n"612
613.balign 4 @ Force a word boundary614str8: .asciz "Selection is %s. Is this OK? (Y or N)\n"615
616.balign 4 @ Force a word boundary617str9: .asciz "A %s has been dispensed with %d cents change.\n\n"618
619.balign 4 @ Force a word boundary620str10: .asciz "Transaction cancelled. Returning %d cents change.\n\n"621
622.balign 4 @ Force a word boundary623str11: .asciz "Total is %d cents.\n\n"624
625.balign 4 @ Force a word boundary626str12: .asciz "The entire inventory reached zero. Terminating the program!\n"627
628.balign 4 @ Force a word boundary629str13: .asciz "%s: %d\n"630
631.balign 4 @ Force a word boundary632str14: .asciz "Error: wiringPiSetup failed! Terminating the program.\n"633
634.balign 4 @ Force a word boundary635strCoke: .asciz "Coke"636
637.balign 4 @ Force a word boundary638strSprite: .asciz "Sprite"639
640.balign 4 @ Force a word boundary641strDrPepper: .asciz "Dr.Pepper"642
643.balign 4 @ Force a word boundary644strCokeZero: .asciz "Coke Zero"645
646@ Input/Output patterns for printf/scanf call647
648.balign 4 @ Force a word boundary649strInPattern: .asciz "%s" @ Character input pattern.650 @ %s is used instead of %c to keep from reading the CR651 @ from the previous input.652
653.balign 4 @ Force a word boundary654readlinePattern: .asciz "%[^\n]" @ Used to clear the input buffer for invalid input.655
656@ Other657
658.balign 4 @ Force a word boundary659charInput: .word 0 @ Memory location to store user input (character)660
661.balign 4 @ Force a word boundary662invalidDump: .skip 100*4 @ Use to clear the input buffer for invalid input663
664.balign 4 @ Force a word boundary665arrInventory: .word 2, 2, 2, 2 @ Array that holds number of each soft drinks666 @ Order: Coke, Sprite, Dr.Pepper, Coke Zero667
668@ Values for the GPIO pins669
670.balign 4671pin2: .word 2672pin3: .word 3673pin4: .word 4674pin5: .word 5675
676.balign 4677buttonBlue: .word 7 @ Blue button678buttonGreen: .word 0 @ Green button679buttonYellow: .word 6 @ Yellow button680buttonRed: .word 1 @ Red button681
682.balign 4683delayMs5000: .word 5000684delayMs1000: .word 1000685delayMs250: .word 250686
687@ Followings are defined in wiringPi.h688
689.extern wiringPiSetup690.extern delay691.extern digitalWrite692.extern pinMode693
694
695.global printf696@ printf("This is printf function, %d %d %d", r1, r2, r3)697@ ----------r0-----------698@ r0-r3 are used as arguments to printf function. When you invoke printf function these699@ register values are likely to be changed. It is a good practice to use other registers700@ than these for the manipulation purposes.701
702.global scanf703
704.end @ End of code and end of file. Leave a blank line after this.