On this page you'll find
everything you would like to know about the programs we've written for this
project.
The software consists of two big parts. One being the
assembler code that is loaded into the PIC
microcontroller. Before you can do anything, you have to make sure that the
program is loaded in the PIC of course. You can do this by using special
programmer boards, the print board is built with an in circuit programming
circuit (ICSP connection). This means you don't have to take the PIC out of the board to
program it, but you can just program it when it's mounted by connecting a
second board. For more info on the electronic design you should go
here.
The other part of the software is the Visual Basic
program that is the interface between the PC and the PIC. Here you
can choose which songs to play or if you want play the guitar by manually
sending note per note to the PIC. It also contains an interface to make the
motor make some steps. This is all explained better in
"How it works", where you can read how
the system works.
If you want to look at the code itself, you can go to the download section, in there you'll find all the code you want. The visual basic zip-file containing the code and an exe. And an assembler zip-file. Containing the ".asm" file with the code and a ".hex" file which you can load into the PIC.
If you want to understand the code perfectly, we suggest you first read this page to get a big idea of how it works, and then go over the program code itself and read the comments in there.
The job the PIC has to do is divided in 3 things. There has to be a way to receive the data sent by the serial connection. Of course this has to work in the other direction as well, so it has to be able to send data through the serial connection so the PC knows what happens. And last but not least, it has to be able to control the motors. This is done by sending pulses to the appropriate control chips. Every pulse is equal to 1 step.
The PC sends 8 bytes to the PIC. The eighth one is a 0-byte so that the PIC can see when all 8 bytes have been received.
The first byte is an initialization byte that tells the PIC which part of the initialization is in progress. Depending on this byte, the PIC will send info back to the PC when a switch is pressed or not.
The second byte is an enable byte. This byte is used to enable/disable all control chips and to reset them.
The third byte tells the PIC which motor has to run at that specific moment.
The fourth byte is a
part of the total number of steps that the motor has to make.
The number of steps to make is determined by two numbers. The first
number says how many cycles of 255 steps we have to make. The second one
says how many steps we have to make extra to that.
The reason we use a format like this is that we can only use 8-bit
numbers. This means only 255 possibilities. This way, by using two
numbers, we can make 255 * 255 + 255 steps in total. This is plenty for
the guitar. The largest amount of steps that have to be made at one time
are only between 350 and 400 steps. So this fourth byte tells how many cycles of 255 steps have to be made.
The fifth byte is also a part of the total number of steps that the motor has to make. This are the extra number of steps that have to be made.
The sixth byte says in which direction the motor has to turn.
The seventh byte says if we need a lot of power or not. (when the motor turns it has to work in high power mode, when it doesn't have to move it has to work in low power mode - this is explained elsewhere on this site)
The assembler code uses
interrupts to receive and transmit data. When the PIC generates an interrupt
it stops its main program and will first execute the interrupt function. In
this function it first stores away all variables that define the current
status of the PIC, like the work-register and the status-register, in
temporary variables. These variables will be put back in their respective
registers when the interrupt ends. That way the main program can take off
again where it was interrupted.
When the PIC generates an interrupt, it looks at which type of interrupt
occurred. We handle four types of interrupts. One of those is the transmit
interrupt, but when that happens the interrupt is ended right away.
Another is the receive
interrupt. When this happens the program will go to the GetData-function
where the data is read. The pic reads one byte at a time. In total it
has to receive 8 bytes every time the PC sends data. This means it has to go
8 times into the GetData function. Here the PIC will shift the data always
to the next DATAIN register until it receives a 0-byte (00000000) from the
PC. This means that the PC has sent 8 bytes and the PIC will go on with the
processing of the sent data. Every time the received byte isn't "00000000",
the PIC will end the interrupt and restore the PIC-status. Immediately after
that, it will generate another receive interrupt.
The processing of the data means that the PIC will put the received data in
the appropriate registers so that they can be used in the main program.
Here the control chips will also be enabled/disabled or be reset when this
has been sent.
The final thing the procedure does is initialize the values for the motor
that has to work. So that when the PIC goes back to the mainloop, it'll be
able to power the right motors and with the right number of steps. The
MOTORX_INIT-procedures make that the current through the motors go up and it
determines the direction it has to turn. It also determines the number of
steps the motor has to make.
There are also two other
interrupts that are being handled. They are the core of the program, namely
TIMER1 and TIMER2. These timers function as the delays in the program.
TIMER2 is an 8-bit timer and is used for small delays, in this case the
length of the pulse we send to the motor. Every time the control chip
gets a pulse from the PIC it will make the motor take 1 step. The length of
this pulse can be made very small.
The TIMER1 is a 16-bit timer and can thus be used for longer delays. In this
case it's the time between two pulses. As explained in the motor part on the
hardware page, we make this time go down when the
number of steps the motor has made goes up. A stepper motor can't start at a
high turning-frequency, it needs a certain acceleration. We use a linear
acceleration to a maximum value. This maximum value is determined by the
maximum speed a motor can handle before it starts to skip steps. In our
case, the limit is the maximum speed of the motor that moves the roll. At
least, it's the limiting speed for motor 1 and 2, respectively the motors
for the moving of the plectrum and the moving of the roll. These two motors
can run at the same time with the same speed and acceleration because the
code for the two motors is intertwined. We choose to make only these 2
motors run at the same time because it would be useless to make the motor
that move the weight up and down and the motor that rotates the plectrum
move at the same time with another motor. That will never happen cause of
the construction.
Thus, those two motors will always run alone. That makes the code a lot
easier.
The code for motor 1 and 2 is adapted to the two motors so that they can
both run at the same time, no matter what. It doesn't matter which motor
starts first, or how many steps they have to make. It always works, which
speeds up the playing enormously of course.
The program sends as many pulses as there are steps to make, which is quite
logically. When the counter for the steps reaches 0, the current through the
motor is made low again and a byte is transmitted to the PC saying that the
motor # has made the needed number of steps.
The main program also checks which of the three switches is pressed.
Depending on the INITIALISE byte sent by the PC, it'll send back info when a
switch is pressed. Depending on the transmitted byte, the PC will know what
just happened. For example which motor is pressed, or which motor made the
required number of steps.
Next to the assembler
code there is also the Visual Basic program. The function of this program is
to create an interface between the PC and the PIC. With the interface we can
send all the info to the PIC and receive info back in the shape of bytes.
The visual basic program has three big modes. Namely,
Automatic mode, to play songs automatically. The info for the songs are stored in a ".song" file. You initialize the system, you load a song and press play. All the rest goes automatically.
Manual mode, to send the notes one at a time. This way you can play your own song, but you have to send note per note manually.
Motor testing mode, this mode is to test the function of the motors. You can define the number of steps each motor has to make here. This is just for testing purposes or for the user to see how the motors work.
The functioning of these three modes are thoroughly explained in the "how it works" page.
The PC sends 8 bytes
always as explained in the part of the assembler
code. The most special one still is the initialise byte. The system
initialises in a few steps as explained in
"how it works". All the motors go to a starting position from where we
know the number of steps to make to get anywhere on the guitar. The motors
keep moving until they hit a switch and then the next motor starts working,
and so on.
When a song is played, we deactivate the switches. Then we just check when a
motor is finished (when a motor has made all the needed steps, the PIC sends
a byte back to the PC, the byte is different of course for every motor).
When a motor finishes, the next motor starts. This asks for a lot of boolean
values of course.
We also use a lot of timers in the program. The explanation of each timer can be found in comments in the Visual Basic code. We still use timers to make the data transfer between PIC and PC a bit less. That makes the system quicker. And since some actions always take the same amount of time (striking the string, moving the weight up or down,...) we can also use a timer for those events.