File transfer push (organization different)
139
1-January/1-13_Notes.md
Executable file
|
@ -0,0 +1,139 @@
|
|||
Opening lectures are gonna be real quick, so listen up
|
||||
|
||||
# Announcements
|
||||
|
||||
- Install arduino IDE
|
||||
- Download PDF for Atmel
|
||||
- buy a binder
|
||||
|
||||
|
||||
|
||||
***Syllabus quiz on Wednesday***
|
||||
|
||||
|
||||
|
||||
# Basics
|
||||
|
||||
Microcontrollers are everywhere.
|
||||
|
||||
Microcontrollers have a processor, and D/A or A/D converters. (digital-analog/vice--versa)
|
||||
|
||||
Essentially any integrated system has a microcontroller
|
||||
|
||||
|
||||
|
||||
The board we used last year is what we're using this year. The microcontroller is the Atmel Atmega 328P. The board itself is still an arduino, but its not the microcontroller.
|
||||
|
||||
The robot we're making a robot with a visualizer, 2 motorized wheels, an IR module, and a Bluetooth module.
|
||||
|
||||
|
||||
|
||||
At the end of the semester, we'll come up with our own project.
|
||||
|
||||
USE www.Arduino.cc A LOT. There's support, code, etc. etc.
|
||||
|
||||
Download the datasheet. There's a lot of pages, so don't print it. Understand it, live with it, sleep with it.
|
||||
|
||||
|
||||
|
||||
# Ports
|
||||
|
||||
## Microcontroller Parts
|
||||
|
||||
They have to have the following
|
||||
|
||||
- Microprocessor
|
||||
- Memory
|
||||
- flash for program storage (stable memory)
|
||||
- RAM for working memory (unstable memory)
|
||||
- **I/O ports**
|
||||
- Built in peripherals
|
||||
- timers
|
||||
- serial interfaces (maybe)
|
||||
- A/D and D/A converters (maybe)
|
||||
|
||||
|
||||
|
||||
What are I/O devices for your PC?
|
||||
|
||||
- Keyboard
|
||||
- Mouse
|
||||
- Screen
|
||||
- etc.
|
||||
|
||||
What are I/O devices for the microcontroller?
|
||||
|
||||
- A/D and D/A for both ins and outs
|
||||
- Anything that isn't self-contained within the microcontroller is an I/O device
|
||||
|
||||
|
||||
|
||||
There are 3 ports that we'll use: B, C, D
|
||||
|
||||
Each microcontroller has 23 pins for I/O
|
||||
|
||||
It is possible to touch the 24th pin, but... just don't.
|
||||
|
||||
==This means that Port C only has 7 pins==
|
||||
|
||||
|
||||
|
||||
Each port can be used pin-by-pin or all of them as a (7 DT 0) vector, or any combination in between.
|
||||
|
||||
In output mode, the program puts either VCC or GND on the pin. In input mode, the program reads the voltage on the pin and determines if its VCC or GND.
|
||||
|
||||
If VCC is 5 and GND is 0, make sure the input is $\pm 2 \%$
|
||||
|
||||
|
||||
|
||||
Standard notation is PXn (Pin Port Pin#)
|
||||
|
||||
|
||||
|
||||
Memorize the pins. Its important.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## Code example
|
||||
|
||||

|
||||
|
||||
What does this do?
|
||||
|
||||
In line order:
|
||||
line 1 is a comment
|
||||
line 2 is a definition for readability. In this case, its naming a pin, in the context of the code. It also removes magic numbers.
|
||||
Line 4-7 is setting up for the loop. Line 5 is defining that pin 13 is an output. (Note: this is not microcontroller pin 5. This is digital pin 13, or PB5.) Line 6 sets an initial state. HIGH and LOW are arduinoC keywords, and 0 and 1 are also acceptable.
|
||||
Line 9-14 is an infinite loop that flashes the LED. Note that the comment is incorrect, and the delay is for $1 \over 2$ seconds. The measurement of delay is in milliseconds.
|
||||
(Note: We will eventually learn how to make this in standard C instead of Arduino C)
|
||||
|
||||
# Syllabus Notes
|
||||
|
||||
Homework: 15%
|
||||
|
||||
Quizzes: 15%
|
||||
|
||||
Hour Exams: 40%
|
||||
|
||||
- 2/7
|
||||
- 3/6
|
||||
- 4/10
|
||||
|
||||
Final Exam: 30%
|
||||
|
||||
|
||||
|
||||
Final Grade:
|
||||
|
||||
- 93%+ = A
|
||||
- 90%+= A-
|
||||
- 87%+= B+
|
||||
- 83%+= B
|
||||
- 80%+= B-
|
||||
- 77%+= C+
|
||||
|
||||
|
||||
|
||||
Final Grade = (attended classes / 40) * grade earned
|
132
1-January/1-15_Notes.md
Executable file
|
@ -0,0 +1,132 @@
|
|||
# Ports
|
||||
|
||||
## Port B
|
||||
|
||||
mainly used for oscillators and timers
|
||||
|
||||
## Port C
|
||||
|
||||
mainly used for A/D conversion or pin change interrupts. (PC6 is an external active low RESET)
|
||||
|
||||
## Port D
|
||||
|
||||
mainly used for communication or pin change interrupts
|
||||
|
||||
|
||||
|
||||
Pins don’t immediately go to high or low. If you aren’t driving it, its an unstable output. As such, there are pull-up resistors, which pulls the value up toward 1.
|
||||
|
||||
Any pushbuttons will use pull-ups.
|
||||
|
||||
|
||||
|
||||
Avoid ports C until we start doing analog.
|
||||
|
||||
|
||||
|
||||
To configure and use Port D, you need to configure PORTD, the data register, DDRD, the data direction register, and the PIND, the port input pin addresses.
|
||||
|
||||
### DDRD - Port D Data Direction Register
|
||||
|
||||
Writing a 1 initializes a pin to make it an output
|
||||
|
||||
Writing a 0 makes the pin an input
|
||||
|
||||
ArduinoC uses the red numbers in the main image. In C, write to the register.
|
||||
|
||||
```c
|
||||
void setup{
|
||||
DDRD = 0b00000010;
|
||||
}
|
||||
```
|
||||
|
||||
### PORTD - Port D Data Register
|
||||
|
||||
Writing a 1 sets the pin high
|
||||
|
||||
writing a 0 sets the pin low
|
||||
|
||||
#### Example
|
||||
|
||||
```c
|
||||
void setup{
|
||||
DDRD = 0xFF;
|
||||
}
|
||||
void loop{
|
||||
PORTD=0x01;
|
||||
delay(1000);
|
||||
PORTD=0xFE;
|
||||
delay(1000);
|
||||
}
|
||||
```
|
||||
|
||||
### PIND - Port D input pin address
|
||||
|
||||
READING a 1 indicates its being driven externally to a high
|
||||
|
||||
READING a 0 indicates its being driven externally to a low
|
||||
|
||||
***DO NOT WRITE TO THIS REGISTER***
|
||||
|
||||
# Masking
|
||||
|
||||
In embedded programming we often need to manipulate individual bits.
|
||||
|
||||
- `~` inversion
|
||||
- `&` AND
|
||||
- use for clearing registers
|
||||
- AND with 1 will leave the bit untouched, and 0s to clear
|
||||
- `|` OR
|
||||
- use for setting specific values in a register
|
||||
- will leave all zeroes alone, only setting 1s
|
||||
- `^` XOR
|
||||
- `>>` shift right
|
||||
- `<<` shift left
|
||||
|
||||
# Code examples
|
||||
|
||||
instead of:
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRD = 0x02;
|
||||
}
|
||||
```
|
||||
|
||||
Use:
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRD |= 0x02;
|
||||
}
|
||||
```
|
||||
|
||||
This does not change initial values already in the system, except for the ones you want it to.
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRD |= 0xFF;
|
||||
}
|
||||
|
||||
void loop(){
|
||||
PORTD |= 0x01;
|
||||
delay(1000);
|
||||
PORTD &= 0xFE;
|
||||
delay(1000);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
Start understanding register programming, as it takes up less space, and is more universally portable.
|
||||
|
||||
## Lab 1 register example
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRB|=0x20; //makes PB5 an output
|
||||
PORTB &= 0xDF; //drives PB5 low
|
||||
}
|
||||
|
||||
```
|
||||
|
32
1-January/1-22_Notes.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Hardware of I/O pin
|
||||
|
||||
A buffer or an amp is a WYSIWYG part. Its used to ensure that the chip doesn’t burn out (Also, ESD protection and amplification).
|
||||
|
||||

|
||||
|
||||
There is also a 3-state buffer. This allows for bi-directional output by having a tri-state out and a buffer in from the same line. This is how bi-directional I/O on the microcontroller works.
|
||||
|
||||
# Inputs and Pullups
|
||||
|
||||
So, we’ve already established how inputs work, using the DDRx (1 for out, 0 for in), PINx (current value), and PORTx (driven value from microcontroller). We’ve also established that pull-ups exist. But how do we force the pin to USE the resistor?
|
||||
|
||||
In ArduinoC, we use the `pinMode(x, INPUT_PULLUP);`. We make the pin an input, then write a 1.
|
||||
|
||||
ex.
|
||||
|
||||
```c
|
||||
DDRD &= 0xFB;
|
||||
PORTD |= 0x04;
|
||||
```
|
||||
|
||||
# Reading Input Pins
|
||||
|
||||
If you want to know the value of pin 2, `AND` the PINx register with a mask, where the mask has a 1 in the positions of the bits you care about, and a 0 in the one’s you don’t. If the result is true, its `HIGH`.
|
||||
|
||||
```c
|
||||
if (PIND & 0x04){};
|
||||
```
|
||||
|
||||
The above `AND`ing function works as such. If ALL of the values are `0` then its `FALSE`. If there is ANY OTHER VALUE, it is `TRUE`.
|
||||
|
||||
In ArduinoC, the function is `digitalRead(pinNumber)`, and will output a high, or a low.
|
53
1-January/1-27_Notes.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
On the resume, don’t put ArduinoC, put C. You worked with the Arduino platform, not the ArduinoC language.
|
||||
|
||||
Here is a step by step for lab 2.
|
||||
|
||||
```c
|
||||
enum {STOP, LED_ON, LED_OFF};
|
||||
int state = STOP, prevState = !state;
|
||||
// This previous state is to define that its the first time in that state
|
||||
boolean isNewState;
|
||||
int stateTimer;
|
||||
boolean isSwPressed, prevIsSwPressed, isSwJustPressed;
|
||||
void setup(){
|
||||
DDRD &= 0xDF;
|
||||
PORTD |= 0x20;
|
||||
DDRB |= 0x08;
|
||||
PORTB &= 0xF7;
|
||||
}
|
||||
|
||||
void loop(){
|
||||
prevIsSwPressed = isSwPressed;
|
||||
isSwPressed = !(PIND & 0x20);
|
||||
isSwJustPressed = (!isSwPressed && prevIsSwPressed);
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
switch(state){
|
||||
case STOP:
|
||||
if(isNewState){
|
||||
Serial.printls("STOP");
|
||||
PORTB &= 0xF7;
|
||||
}
|
||||
if(isSwJustPressed) state = LED_ON;
|
||||
break;
|
||||
case LED_ON:
|
||||
if(isNewState){
|
||||
stateTimer = 0;
|
||||
Serial.println("LED_ON");
|
||||
PORTB |= 0x04;
|
||||
}
|
||||
stateTimer++;
|
||||
if (isSwJustPressed){
|
||||
PORTB &= 0xF7;
|
||||
state = STOP;
|
||||
}
|
||||
if (stateTimer >= 250) state = LED_OFF;
|
||||
break;
|
||||
default: state = STOP;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
BIN
1-January/1-29_Notes.assets/outputCompareRegister.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
1-January/1-29_Notes.assets/timerStructure.png
Normal file
After Width: | Height: | Size: 18 KiB |
87
1-January/1-29_Notes.md
Normal file
|
@ -0,0 +1,87 @@
|
|||
# Counters and Timers
|
||||
|
||||
Its the same internal structure. The difference is whether its connected to system clock or an external event.
|
||||
|
||||

|
||||
|
||||
But whats wrong with delays? Delays stop everything the CPU is doing. The timers don’t. When they hit the “time”, they interrupt, but it lets things run instead of it.
|
||||
|
||||
There are 3 timers.
|
||||
|
||||
timer/counter 0 and 2 are 8bit, with a 256 step resolution. Timer/counter 1 is a 16 bit timer, with a 65k step resolution.
|
||||
|
||||
|
||||
|
||||
==**Remember: Frequency = 1/time**==
|
||||
|
||||
==The clock on the arduino is 16Mhz. This works out to 62.5ns. This will most likely be tested on.==
|
||||
|
||||
|
||||
|
||||
TCNTn is the generic way of referring to a counter register. You can read or write to this register. This makes something like a stopwatch easy to implement. (write 0s, do something, read the register)
|
||||
|
||||
|
||||
|
||||
Timer0 and Timer2 will roll over after $16\mu s$, so don’t expect it to go farther than that. Timer1 is for long-term timing (maxes out at 1ms)
|
||||
|
||||
But timers aren’t this simple. You can do more fun things with them, and less difficult things as well.
|
||||
|
||||
## Timer Registers
|
||||
|
||||
### Output Comparator Registers
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
You can set OCRnA and OCRnB to a specific value. When the TCNT hits the value in OCR, then the OCF will go high. The TOV goes high to let you know that the TCNT has rolled over.
|
||||
|
||||
Timer0 information:
|
||||
|
||||
- `TCNT0`
|
||||
- `OCR0A`
|
||||
- `OCR0B`
|
||||
|
||||
Timer2 information:
|
||||
|
||||
- `TCNT2`
|
||||
- `OCR2A`
|
||||
- `OCR2B`
|
||||
|
||||
Timer1 information:
|
||||
|
||||
- `TCNT1H` (15:8)
|
||||
- `TCNT1L` (7:0)
|
||||
- `OCR1AH`
|
||||
- `OCR1AL`
|
||||
- `OCR1BH`
|
||||
- `OCR1BL`
|
||||
|
||||
### Timer Control Registers
|
||||
|
||||
`TCCRnA` and `TCCRnB` control the functionality of the timers.
|
||||
|
||||
- the mode of operation
|
||||
- what to do on compare match
|
||||
- force output compare
|
||||
- fast PWM mode
|
||||
- Phase Corrected PWM mode
|
||||
- more that haven’t been discussed (:sadface:)
|
||||
|
||||
#### Normal mode
|
||||
|
||||
Simplest. Counter counts, then rolls over.
|
||||
|
||||
Used for counting ticks.
|
||||
|
||||
#### CTC mode
|
||||
|
||||
clears timer to 0 when `TCNTn ` matches `OCRnA`.
|
||||
|
||||
|
||||
|
||||
Eventually, we’ll use Fast PWM, and Phase Corrected PWM once or twice, but these are about it.
|
||||
|
||||
|
||||
|
||||
`TCCRnB` does clock-division, while `TCCRnA` does the above shown tasks.
|
BIN
1-January/1-31_Notes.assets/clockOutput.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
1-January/1-31_Notes.assets/clockScaling.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
1-January/1-31_Notes.assets/image-20200113102850434.png
Executable file
After Width: | Height: | Size: 247 KiB |
BIN
1-January/1-31_Notes.assets/outputMode.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
1-January/1-31_Notes.assets/preScaler.png
Normal file
After Width: | Height: | Size: 78 KiB |
69
1-January/1-31_Notes.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
# ==END OF WEEK 3==
|
||||
|
||||
---
|
||||
|
||||
# Normal Mode
|
||||
|
||||
- Constant incrementing
|
||||
- rollover when clock-space filled
|
||||
- TIFRx bit 0 returns whether the timer has overflowed. ==***Reset this by writing a 1***==
|
||||
- Write to the TCNTx to set when the timer should reset. The number is to be subtracted from the timers max before writing. For example
|
||||
- 160 count timer: $255-160=95$
|
||||
- `TCNT0 = 95;`
|
||||
- `if (TIRF0 & 0x01)`
|
||||
- `TIFR0 |=0x01;`
|
||||
- This will reset the overflow bit
|
||||
|
||||
## Code Example ($10\mu s$ delay)
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
//initialize i/o
|
||||
//initialize timer
|
||||
}
|
||||
|
||||
void loop(){
|
||||
//do stuff
|
||||
TCNT0 = 95;
|
||||
while ((TIFR0 & 0x01) == 0); //wait for 10us
|
||||
TIFR0 |= 0x01;
|
||||
//do more stuff
|
||||
}
|
||||
```
|
||||
|
||||
Still inefficient, but interrupts are something we don’t know yet
|
||||
|
||||
# CTC Mode
|
||||
|
||||
- Counts up from 0 until it reaches `OCRnA`. When they’re equal, `TCNTn` is set back to 0, and the `OCFxA` is set, and counting resets
|
||||
- Can be used to output a square wave. The output inverts every time `TCNTn` reaches `OCRnA`
|
||||
|
||||
# Controlling outputs
|
||||
|
||||

|
||||
|
||||
Pins `PD3`, `PD5`, `PD6`, `PB1`, `PB2`, and `PB3` are connected to timers.
|
||||
|
||||
3 bit waveform generation:
|
||||
|
||||

|
||||
|
||||
`WGM02` is bit 3 in `TCCRxB`. `WGM01` and `WGM00` are bits 1 and 0 respectively in `TCCRnA`
|
||||
|
||||
Setting Prescaler:
|
||||
|
||||

|
||||
|
||||
`TCCRnA` bits 7 and 6 are how to set the output pin for `OCnA`. bits 5 and 4 are for `OCnB`, and have the same table.
|
||||
|
||||

|
||||
|
||||
# Clock Scaling
|
||||
|
||||
Each timer has prescaling options to divide down the clock
|
||||
|
||||
$t_{elapsed}=cnt\times{N\over16MHz}$
|
||||
|
||||
The prescaler for the clock is bits 2-0 in `TCCRnB`
|
||||
|
||||

|
BIN
1-January/clockOutput.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
1-January/clockScaling.png
Normal file
After Width: | Height: | Size: 37 KiB |
11
1-January/homework1.md
Executable file
|
@ -0,0 +1,11 @@
|
|||
# Skyler MacDougall
|
||||
|
||||
## Homework 1 : due 1/22/2020
|
||||
|
||||
1. Research some widely used microcontrollers, and compare and contrast their performance.
|
||||
|
||||
After significant research, I was unable to find two microcontrollers with easily comparable performance numbers, such as some form of MIPS.
|
||||
|
||||
3. Create an invention using a microcontroller. Describe your invention and the role the microcontroller plays in the invention.
|
||||
|
||||
My invention would be a switch that keeps itself flipped in one direction. It is a box containing a switch, a flap, and an actuator. When the switch is flipped, the flap would open, and the actuator would flip the switch back to its original position. The microcontroller would control the flap and the actuator.
|
BIN
1-January/homework1.pdf
Normal file
BIN
1-January/image-20200113102924585.png
Executable file
After Width: | Height: | Size: 34 KiB |
BIN
1-January/outputCompareRegister.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
1-January/outputMode.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
1-January/preScaler.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
1-January/timerStructure.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
1-January/triState.png
Normal file
After Width: | Height: | Size: 14 KiB |
66
2-February/2-10_Notes.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
# PWM
|
||||
|
||||
But why tho?
|
||||
|
||||
- power efficiency
|
||||
- having the light off 10% of the time
|
||||
- fade/dim instead of blink
|
||||
- variable speed motors
|
||||
- non-square audio waves
|
||||
|
||||
|
||||
|
||||
Signal toggles extremely fast, and is observed as a rough sine wave
|
||||
|
||||
|
||||
|
||||
frequency is how often it pulses
|
||||
|
||||
duty cycle is how much of the frequency is high
|
||||
|
||||
|
||||
|
||||
## Pins used by PWM
|
||||
|
||||
- PD3
|
||||
- OC2B
|
||||
- PD5
|
||||
- OC0B
|
||||
- PD6
|
||||
- OC0A
|
||||
- PB1
|
||||
- OC1A
|
||||
- PB2
|
||||
- OC1B
|
||||
- PB3
|
||||
- OC2A
|
||||
|
||||
|
||||
|
||||
# Fast PWM mode (0 & 2)
|
||||
|
||||
## Mode 3
|
||||
|
||||
OCRA or OCRB determine when it comes down from 1. It goes back up to 1 when the timer rolls over
|
||||
|
||||
# Mode 7
|
||||
|
||||
OCRB sets when to come down from 1. OCRA says to go back to 1
|
||||
|
||||
|
||||
|
||||
Non-inverting is standard (see above), inverting is the opposite of above
|
||||
|
||||
|
||||
$$
|
||||
f_{OCnxPWM}={f_{clkI/O}\over N\times count_{clock}}
|
||||
$$
|
||||
|
||||
# Servos
|
||||
|
||||
20ms PWM period
|
||||
|
||||
1-2ms duty cycle
|
||||
|
||||
|
||||
|
88
2-February/2-12_Notes.md
Normal file
|
@ -0,0 +1,88 @@
|
|||
# Modes of Operation review
|
||||
|
||||
- **==Normal mode==**
|
||||
- simplest mode
|
||||
- counter counts to 255/2^16^ and then rolls over
|
||||
- used most when you’re counting ticks or timing an event
|
||||
- **==CTC==**
|
||||
- counter cleared when `TCNT==OCRA | OCRB`
|
||||
- used to create waveforms and interrupts
|
||||
- **==Fast PWM==**
|
||||
- creates a waveform with fixed frequency and variable duty cycle
|
||||
- Toggles high and low quickly enough that only an average voltage is detected
|
||||
|
||||
# Timer configuration checklist
|
||||
|
||||
- [ ] consult datasheet registers
|
||||
|
||||
- [ ] decide the timer to use
|
||||
|
||||
- [ ] default to T1
|
||||
- [ ] if 8 bits is fine, use T0 or T2
|
||||
|
||||
- [ ] Decide which mode you need
|
||||
|
||||
- counting or timing?
|
||||
- [ ] normal mode (no configuration)
|
||||
|
||||
- Are you using the timer as a time base or frequency generator?
|
||||
- [ ] Use CTC mode
|
||||
- Are using the timer for PWM?
|
||||
- [ ] PWM mode… duh
|
||||
|
||||
- [ ] Direct output pins?
|
||||
|
||||
- [ ] `COMA`
|
||||
- [ ] `COMB`
|
||||
- [ ] Determine which clock speed devisor you need
|
||||
- [ ] set in `TCCRB`
|
||||
- [ ] Set a default for `OCRA/OCRB`
|
||||
- [ ] Set the pins to output mode
|
||||
|
||||
- [ ] interrupts?
|
||||
|
||||
- [ ] `cli();`
|
||||
- [ ] Write to `TIMSK`
|
||||
- [ ] Enable counter overflow interrupt in normal mode
|
||||
- [ ] enable output compare interrupts in PWM/CTC mode
|
||||
- [ ] `sei();`
|
||||
- [ ] Write `ISR` function
|
||||
|
||||
|
||||
|
||||
# PWM mode in T1
|
||||
|
||||
Many different PWM modes. Todays focus:
|
||||
|
||||
- mode 5 (8-bit top)
|
||||
- mode 6 (9-bit top)
|
||||
- mode 7 (10-bit top)
|
||||
- mode 14 (`ICR1` top)
|
||||
- mode 15 (`OCR1A` top)
|
||||
|
||||
|
||||
|
||||
Frequency is fixed in modes 5, 6, 7. `OCR1A/OCR1B` determines the duty cycle.
|
||||
|
||||
In mode 14, `ICR1` sets the frequency, and `OCR1A/OCR1B` determines the duty cycle.
|
||||
|
||||
In the above, the duty cycle determines the pin.
|
||||
|
||||
|
||||
|
||||
In mode 15, `OCR1A` sets the frequency, and `OCR1B` is used to set the duty cycle. The output pin is always `OCR1B/PB2`
|
||||
|
||||
|
||||
|
||||
# Question
|
||||
|
||||
20ms period. What mode, and what scale for the clock?
|
||||
|
||||
I would use mode 15, so the prescaler is easy to set, and the output pin is defined.
|
||||
$$
|
||||
4ms=prescale_1;\ 32ms=prescale_8;\ 262ms=prescale_{64}\\
|
||||
1s=prescale_{256};\ 4s=prescale_{1024}\\
|
||||
4ms\le20ms\le32ms\\
|
||||
\therefore\\
|
||||
prescaler=8
|
||||
$$
|
8
2-February/2-12_inClassProblem.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Question
|
||||
|
||||
20ms period. What mode, and what scale for the clock?
|
||||
|
||||
I would use mode 15, so the prescaler is easy to set, and the output pin is defined.
|
||||
$$
|
||||
4ms=prescale_1;\ 32ms=prescale_8;\ 262ms=prescale_{64}\\1s=prescale_{256};\ 4s=prescale_{1024}\\4ms\le20ms\le32ms\\\therefore\\prescaler=8
|
||||
$$
|
15
2-February/2-14_inClassProblem.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
1. 60 second timer
|
||||
|
||||
- (15) 4 second timers.
|
||||
- main waits for a button, then runs the code, then waits again
|
||||
|
||||
```c
|
||||
|
||||
```
|
||||
|
||||
2. copy above, but drive the LED using the PWM signal
|
||||
|
||||
```c
|
||||
|
||||
```
|
||||
|
57
2-February/2-17_Notes.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Interrupts vs Polling
|
||||
|
||||
Interrupts provide priority, free up the CPU, and let you complete tasks faster
|
||||
|
||||
Where do interrupts come from?
|
||||
|
||||
- A/D converters
|
||||
- Timers/counters
|
||||
- Push buttons
|
||||
- Sensors
|
||||
- etc.
|
||||
|
||||
|
||||
|
||||
Only one interrupt at a time. (Except RESET, but thats… different)
|
||||
|
||||
Interrupts do the following
|
||||
|
||||
- stores and shuts down all processes
|
||||
- runs ISR
|
||||
- restores programs
|
||||
|
||||
|
||||
|
||||
# Pin Change Interrupts
|
||||
|
||||
`pinState != prevPinState`
|
||||
|
||||
Pin interrupts are grouped together in banks (these are the same as the ports).
|
||||
|
||||
`INT0` and `INT1` can trigger on specific points (Rising/falling edge, toggle, or cont. low), with second highest priority interrupt
|
||||
|
||||
|
||||
|
||||
==MULTIPLE PINS SHARE INTERRUPT VECTORS==
|
||||
|
||||
`PCINT0`=`PCINT0_vect`
|
||||
|
||||
`PCINT1`=`PCINT1_vect`
|
||||
|
||||
`PCINT2`=`PCINT2_vect`
|
||||
|
||||
|
||||
|
||||
`PCMSKn` tells the microcontroller what pins are valid interrupts. Essentially, an enable for the interrupts.
|
||||
|
||||
`PCICRn` turns on the individual interrupt
|
||||
|
||||
## Set pin change interrupts
|
||||
|
||||
1. `cli()`
|
||||
2. Enable `PCICR`
|
||||
3. set pins `PCMSKn`
|
||||
4. `sei()`
|
||||
|
||||
|
||||
|
BIN
2-February/2-19_Notes.assets/codeBlock1.png
Normal file
After Width: | Height: | Size: 139 KiB |
76
2-February/2-19_Notes.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
# External Interrupts
|
||||
|
||||
These are PD2 and PD3. labeled as `INTn` with the logical vector.
|
||||
|
||||
Changing bits 1 and 0 in `EIMSK` enables those interrupts. `EICRA` determines when the interrupt is triggered.
|
||||
|
||||
|
||||
|
||||
steps:
|
||||
|
||||
- [ ] `cli();`
|
||||
- [ ] Enable your specific detection mode `EICRA`
|
||||
- [ ] set appropriate bits in `EIMSK`
|
||||
- [ ] `sei();`
|
||||
|
||||
|
||||
|
||||
# Volatile and Static variables
|
||||
|
||||
## Volatile
|
||||
|
||||
Denotes variables changable in the ISR.
|
||||
|
||||

|
||||
|
||||
## Static
|
||||
|
||||
used when a variable should keep its value between ISR calls
|
||||
|
||||
# Coding problem
|
||||
|
||||
Create a game show setup
|
||||
|
||||
- [ ] each contestant has the ability to force PD4-PD7 low
|
||||
- [ ] first to buzz in lights up PB0-PB3 respectively
|
||||
- [ ] interrupt definition for who buzzed first
|
||||
|
||||
Tasks
|
||||
|
||||
- [x] initialize ports
|
||||
- [x] initialize interrupts
|
||||
- [x] write ISR
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRB |= 0x0F;
|
||||
DDRD &= 0x0F;
|
||||
PORTB &= 0xF0;
|
||||
PORTD |= 0xF0;
|
||||
cli();
|
||||
PCICR = 4;
|
||||
PCMSK2 = 0xF0;
|
||||
sei();
|
||||
}
|
||||
|
||||
void loop(){
|
||||
while(1){}
|
||||
}
|
||||
|
||||
ISR(PCINT2_vect){
|
||||
byte inputPins = PIND;
|
||||
if(inputPins & 0x10) {
|
||||
PORTB |= 0x01;
|
||||
PORTB &= 0xF1;
|
||||
}
|
||||
if(inputPins & 0x20) {
|
||||
PORTB |= 0x02;
|
||||
PORTB &= 0xF2;
|
||||
}
|
||||
if(inputPins & 0x40) {
|
||||
PORTB |= 0x04;
|
||||
PORTB &= 0xF4;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
47
2-February/2-19_inClassProblem.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Coding problem
|
||||
|
||||
Create a game show setup
|
||||
|
||||
- [x] each contestant has the ability to force PD4-PD7 low
|
||||
- [x] first to buzz in lights up PB0-PB3 respectively
|
||||
- [x] interrupt definition for who buzzed first
|
||||
|
||||
Tasks
|
||||
|
||||
- [x] initialize ports
|
||||
- [x] initialize interrupts
|
||||
- [x] write ISR
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRB |= 0x0F;
|
||||
DDRD &= 0x0F;
|
||||
PORTB &= 0xF0;
|
||||
PORTD |= 0xF0;
|
||||
cli();
|
||||
PCICR = 4;
|
||||
PCMSK2 = 0xF0;
|
||||
sei();
|
||||
}
|
||||
|
||||
void loop(){
|
||||
while(1){}
|
||||
}
|
||||
|
||||
ISR(PCINT2_vect){
|
||||
byte inputPins = PIND;
|
||||
if(inputPins & 0x10) {
|
||||
PORTB |= 0x01;
|
||||
PORTB &= 0xF1;
|
||||
}
|
||||
if(inputPins & 0x20) {
|
||||
PORTB |= 0x02;
|
||||
PORTB &= 0xF2;
|
||||
}
|
||||
if(inputPins & 0x40) {
|
||||
PORTB |= 0x04;
|
||||
PORTB &= 0xF4;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
BIN
2-February/2-19_inClassProblem.pdf
Normal file
99
2-February/2-21_inClassProblem.md
Normal file
|
@ -0,0 +1,99 @@
|
|||
# Skyler MacDougall
|
||||
|
||||
## 2-21-2020 In Class Problem
|
||||
|
||||
Assume the following setup:
|
||||
|
||||
```c
|
||||
TCCR1A = 0b00100011;
|
||||
TCCR1B = 0b00011011;
|
||||
OCR1A = 9999;
|
||||
OCR1B = 2499;
|
||||
```
|
||||
|
||||
1. What mode is the timer in?
|
||||
|
||||
Fast PWM (OCR1A top)
|
||||
|
||||
2. What is the prescaler?
|
||||
|
||||
256
|
||||
|
||||
3. What is the period?
|
||||
|
||||
6.25s
|
||||
|
||||
4. What is the pulse width?
|
||||
|
||||
1.5625s
|
||||
|
||||
5. What is the duty cycle?
|
||||
|
||||
25%
|
||||
|
||||
6. On which pin will the output wave appear?
|
||||
|
||||
digital pin 10 (SS/OC1B/PCINT2) PB2
|
||||
|
||||
7. In Timer1, what is the difference between modes 5, 6, and 7?
|
||||
|
||||
Bit depth. Mode 5 has a bit-depth of 8; Mode 6, 9; Mode 7, 10.
|
||||
|
||||
8. What is the minimum PWM frequency that can be achieved with Timer0 or Timer2?
|
||||
|
||||
$$
|
||||
\frac{1}{256\times\frac{1024}{16MHz}}=f\\
|
||||
f\approx61Hz
|
||||
$$
|
||||
|
||||
9. What is the minimum PWM frequency that can be achieved with Timer1?
|
||||
|
||||
$$
|
||||
\frac{1}{2^{16}\times\frac{1024}{16MHz}}=f\\
|
||||
f\approx238mHz
|
||||
$$
|
||||
|
||||
10. Write the C code to achieve the following:
|
||||
|
||||
- [x] Use a PWM wave to control the brightness of an LED connected to pin PD6
|
||||
|
||||
- [x] The LED is at 10% brightness at the start of the program.
|
||||
- [x] There is one pushbutton connected to INT0 and one connected to INT1.
|
||||
- [x] each time INT0 is pressed, an interrupt increases the brightness of the LED by 10%
|
||||
- [x] each time INT1 is pressed, an interrupt decreases the brightness of the LED by 10%
|
||||
- [x] the brightness cannot go below 10% or above 90%
|
||||
|
||||
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
TCCR0A = 0b10000011;
|
||||
TCCR0B = 0b00000001;
|
||||
OCR0A = 25;
|
||||
TCNT0 = 0;
|
||||
cli();
|
||||
EICRA = 0;
|
||||
EIMSK = 3;
|
||||
sei();
|
||||
}
|
||||
|
||||
void loop(){
|
||||
while(1);
|
||||
}
|
||||
|
||||
ISR(INT1_vect){
|
||||
if(OCR0A > 25){
|
||||
OCR0A -= 25;
|
||||
}
|
||||
}
|
||||
|
||||
ISR(INT0_vect){
|
||||
if(OCR0A < 230){
|
||||
OCR0A += 25;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
11. Could you swap out the LED in the previous program and have it work the same (without changing the code)?
|
||||
|
||||
From my experience with servos from homework and lab; no, because the servos don’t react to a PWM signal in the intended way, and will most likely act extraneously.
|
BIN
2-February/2-21_inClassProblem.pdf
Normal file
26
2-February/2-21_inClassProblem/2-21_inClassProblem.ino
Normal file
|
@ -0,0 +1,26 @@
|
|||
void setup(){
|
||||
TCCR0A = 0b10000011;
|
||||
TCCR0B = 0b00000001;
|
||||
OCR0A = 25;
|
||||
TCNT0 = 0;
|
||||
cli();
|
||||
EICRA = 0;
|
||||
EIMSK = 3;
|
||||
sei();
|
||||
}
|
||||
|
||||
void loop(){
|
||||
while(1);
|
||||
}
|
||||
|
||||
ISR(INT1_vect){
|
||||
if(OCR0A > 25){
|
||||
OCR0A -= 25;
|
||||
}
|
||||
}
|
||||
|
||||
ISR(INT0_vect){
|
||||
if(OCR0A < 230){
|
||||
OCR0A += 25;
|
||||
}
|
||||
}
|
BIN
2-February/2-24_Notes.assets/dataPacketFormat.png
Normal file
After Width: | Height: | Size: 27 KiB |
58
2-February/2-24_Notes.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
# I^2^C
|
||||
|
||||
Inter integrated circuits
|
||||
|
||||
- standard serial bus protocol
|
||||
- enables communication between microprocessor and peripherals
|
||||
- 2 wires in the interface
|
||||
- clock
|
||||
- `SCL ` or `SCLK`
|
||||
- provided by master
|
||||
- uni-directional
|
||||
- data
|
||||
- `SDA` or `SDAT`
|
||||
- bi-directional
|
||||
- inexpensive and simple
|
||||
|
||||
Arduino calls it 2-wire serial interface
|
||||
|
||||
Broadcasting is possible
|
||||
|
||||
Data should only change when `SCLK` is low. Both signals idle high. The master initiates the transfer by pulling `SDAT` low while holding `SCLK` high. To end the transmission the master pulls `SCLK` high.
|
||||
|
||||

|
||||
|
||||
Step 1 establishes the location of the device. Step 2 defines where in the memory needs to be written to the device. Step 3 actually writes to the device. (This is for writes only. Reads are the same)
|
||||
|
||||
|
||||
|
||||
On a write, the peripheral pulls data low every 9th bit. On a read, the master pulls data low on the 9th bit (except on the last one, where it pulls high to disconnect). If you don’t disconnect (`NAK`), you can do a register dump, in or out. If you’re doing this, its recommended to start in internal address `0`. You can start wherever you like, but you can only increment in register counts.
|
||||
|
||||
|
||||
|
||||
The master begins by sending start, the peripheral address, and a singular bit to establish data transfer direction (1 to read, 0 to write). The peripheral device whose address matches the address sent by the master will answer with an `ACK`. After the peripheral `ACK`s, data transfer takes place in the direction specified, and it takes 9 cycles for one byte. The master completes communication by sending a `STOP` signal.
|
||||
|
||||
|
||||
|
||||
To allow for continued communications, there is a repeated start. Send the `SCLK` high, and pull the `SDAT` low.
|
||||
|
||||
|
||||
|
||||
In order to read, you have to point the address to the correct location, so you start with a write command. After this, you restart, and request a read.
|
||||
|
||||
|
||||
|
||||
The pins on the board are on the end, past the digital pins, and on the other side, its next to the `GVS` male pins.
|
||||
|
||||
|
||||
|
||||
To initialize properly, do the following:
|
||||
|
||||
```c
|
||||
DDRC &= 0b11001111;
|
||||
PORTC |= 0b00110000;
|
||||
//arduinoCode
|
||||
pinMode(A4, INPUT_PULLUP);
|
||||
pinMode(A5, INPUT_PULLUP);
|
||||
```
|
||||
|
111
2-February/2-26_Notes.md
Normal file
|
@ -0,0 +1,111 @@
|
|||
# I^2^C Bus Speeds
|
||||
|
||||
## Standards
|
||||
|
||||
Original Standard: 100kHz
|
||||
|
||||
Fast Mode: 400kHz
|
||||
|
||||
Fast Mode Plus: 1MHz
|
||||
|
||||
High-speed mode: 3.4MHz[^1]
|
||||
|
||||
Ultra Fast mode: 5MHz [^1]
|
||||
|
||||
## Setting bus speed
|
||||
|
||||
`TWBR` defines the bit rate for the two wire interface (`TWI`).
|
||||
$$
|
||||
SCL= \frac{clock}{16+2(TWBR)\times prescale}\\
|
||||
assume\ prescale=1\\
|
||||
TWBR={\frac{16MHz}{bitrate}-16\over2}
|
||||
$$
|
||||
|
||||
|
||||
# TWI enable
|
||||
|
||||
`TWCR` is the `TWI` control register.
|
||||
|
||||
==ONLY CHANGE `TWEN` WHEN YOU WANT TO TURN OFF `TWI`==
|
||||
|
||||
`TWINT` sets when its finished its current job and expects application software response.
|
||||
|
||||
`TWSTA` is the start bit.
|
||||
|
||||
`TWSTO` is the stop bit.
|
||||
|
||||
`TWDR` (register) contains the data that you wish to send or receive.
|
||||
|
||||
# Important Code blocks
|
||||
|
||||
```c
|
||||
void initI2C (unsigned long bit_rate){
|
||||
TWBR = ((16000000/bit_rate)-16)/2; //TWBR set
|
||||
TWCR |= 0b00000100;
|
||||
DDRC &= 0b11001111;
|
||||
PORTC |= 0b00110000; //initialize pins PC4/PC5 as pullups (clocks idle high)
|
||||
}
|
||||
|
||||
void i2cWaitForComplete(){
|
||||
while(!(TWCR & 0x80)){} //wait until TWINT is true
|
||||
}
|
||||
|
||||
void i2cStart(){
|
||||
TWCR = 0b10100100; //clear interrupt, initiate start, enable TWI
|
||||
i2cWaitForComplete(); //wait to know start is complete
|
||||
}
|
||||
|
||||
void i2cStop(){
|
||||
TWCR = 0b10010100; //clear interrupt, initiate stop, enable TWI
|
||||
}
|
||||
|
||||
void i2cSend(byte data){
|
||||
TWDR = data;
|
||||
TWCR = 0b10000100; //clear interrupt and enable
|
||||
i2cWaitForComplete(); //wait to know data is sent
|
||||
}
|
||||
|
||||
byte i2cReadAck(){ //multi-read
|
||||
TWCR = 0b11000100; //clear interrupt, allow ACK, enable TWI
|
||||
i2cWaitForComplete(); //wait to know data is recieved
|
||||
return(TWDR); //return recieved data
|
||||
}
|
||||
|
||||
byte i2cReadNoAck(){ //single read (always done eventually)
|
||||
TWCR = 0b10000100; //clear interrupt, enable TWI
|
||||
i2cWaitForComplete(); //wait to know data is recieved
|
||||
return(TWDR); //return recieved data
|
||||
}
|
||||
```
|
||||
|
||||
## Example code in use
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
Serial.begin(9600);
|
||||
initI2C(100000);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
i2cStart();
|
||||
i2cSend(MPU6050_address_W);
|
||||
i2cSend(WHOAMI);
|
||||
i2cStart();
|
||||
i2cSend(MPU6050_address_R);
|
||||
read_data = i2cReadNoAck();
|
||||
i2cStop();
|
||||
if(read_data == 0x68)
|
||||
Serial.println("MPU Successfully connected!");
|
||||
else
|
||||
Serial.println("MPU not connected. Check your setup.");
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[^1]:Note that this is not possible on our boards, due to overhead and max clock speed of our chip
|
||||
|
||||
|
||||
|
83
2-February/2-3_Notes.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
# Interrupts
|
||||
|
||||
Better than polling, because it uses less resources. But building an interrupt structure means we need a priority structure.
|
||||
|
||||
|
||||
|
||||
Lower value = interrupt faster, with higher priority
|
||||
|
||||
reset has the highest priority
|
||||
|
||||
|
||||
|
||||
## Interrupt steps
|
||||
|
||||
- current program halts
|
||||
- registers stored
|
||||
- program execution is passed to an Interrupt Routine (ISR)
|
||||
- each interrupt capable event has an ISR
|
||||
- When the ISR completes execution
|
||||
- interrupt is turned off
|
||||
- registers are restored
|
||||
- original program picks up where it was
|
||||
|
||||
## Programmer’s job
|
||||
|
||||
- Write to the ISR
|
||||
- its a function, but not explicitly called
|
||||
- `sei()` for turning on global interrupts
|
||||
- `cli()` for turning off global interrupts
|
||||
|
||||
|
||||
|
||||
# Programming Interrupts
|
||||
|
||||
3 enables for interrupt;
|
||||
|
||||
- overflow interrupt (`TIMSKn0`)
|
||||
- OCA interrupt (`TIMSKn1`)
|
||||
- OCB (`TIMSKn2`)
|
||||
|
||||
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
cli();//turn off global interrupts
|
||||
//set interrupt flag(s) in TIMSKn
|
||||
sei();//turn on global interrupts again
|
||||
}
|
||||
|
||||
ISR()//vector name (slide 13)
|
||||
{
|
||||
//K.I.S.S. Minimize lines
|
||||
}
|
||||
|
||||
void loop(){
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## In class coding
|
||||
|
||||
Write a program to use interrupts to toggle an LED connected to PD2 every second
|
||||
|
||||
```c
|
||||
void setup()
|
||||
{
|
||||
cli();
|
||||
TIMSK1 |= 0x02;
|
||||
TIFR1 |= 0x02;
|
||||
sei();
|
||||
DDRD |= 0x04;
|
||||
TCCR1A = 0x42;
|
||||
TCCR1B = 0x8C;
|
||||
OCR1A = 31249;
|
||||
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
PORTD = PORTD ^ 0x04;
|
||||
}
|
||||
```
|
||||
|
25
2-February/2-3_inClassProblem.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# In class coding
|
||||
|
||||
Write a program to use interrupts to toggle an LED connected to PD2 every second
|
||||
|
||||
```c
|
||||
void setup()
|
||||
{
|
||||
cli();
|
||||
TIMSK1 |= 0x02;// correct
|
||||
TIFR1 |= 0x02;
|
||||
sei();
|
||||
DDRD |= 0x04; // correct
|
||||
TCCR1A = 0x00; // wrong: 0x42;
|
||||
TCCR1B = 0x0C; // wrong: 0x8C;
|
||||
OCR1A = 62499;// wrong. 31249 needs to be doubled
|
||||
TCNT1 = 0; // also needed
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
PORTD = PORTD ^ 0x04;
|
||||
//PORTD ^= 0x04; is easier, and is acceptable
|
||||
}
|
||||
```
|
||||
|
BIN
2-February/2-3_inClassProblem.pdf
Normal file
63
3-March/3-2_Notes.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# A-D Converters
|
||||
|
||||
==Not on the upcoming exam==
|
||||
|
||||
==HW7 due in 3 weeks==
|
||||
|
||||
==HW8 is individual. Fill out one for each of your group members==
|
||||
|
||||
Analog signals are inherently not digital. In electrical systems, analog signals are represented by a voltage that is proportional to its intensity.
|
||||
|
||||
|
||||
|
||||
Digital signals are discrete. A digital representation is the result of a number of limited precision to a continuously variable quantity.
|
||||
|
||||
|
||||
|
||||
## Digitizing
|
||||
|
||||
periodic sampling to approximate the value
|
||||
|
||||
More samples is more better-er
|
||||
|
||||
|
||||
|
||||
Sampling rate must be at least twice as high as the highest frequency you want to represent.
|
||||
|
||||
Bare minimum spec, and you can go higher.
|
||||
|
||||
|
||||
|
||||
## Hardware
|
||||
|
||||
hardware exists to convert analog to digital
|
||||
|
||||
it can be a standalone component, and is built into many microcontrollers
|
||||
|
||||
There’s different ways that it can be done, but we will focus on *successive Approximation ADC*
|
||||
|
||||
|
||||
|
||||
ex.
|
||||
|
||||
Voltage Range = 0-10
|
||||
|
||||
I have a voltage in that range, we successfully divide by two until we find essentially the same number.
|
||||
|
||||
We’re inputting a 7.65V source.
|
||||
|
||||
We’re gonna cut it in half, then we compare to the source. If its higher, write a 1, take the divided number, and set as the lower bound. If its lower, write a 0, take the divided number, set as the upper bound.
|
||||
$$
|
||||
{(10+0)\over2}=5<7.65;\ 1\\
|
||||
{(10+5)\over2}=7.5<7.65;\ 1\\
|
||||
{(10+7.5)\over2}=8.75>7.65;\ 0\\
|
||||
{(8.75+7.5)\over2}=8.125>7.65;\ 0\\
|
||||
{(8.125+7.5)\over2}=7.8125>7.65;\ 0\\
|
||||
{(7.8125+7.5)\over2}=7.65625>7.65;\ 0\\
|
||||
{(7.65625+7.5)\over2}=7.578125<7.65;\ 1\\
|
||||
{(7.65625+7.578125)\over2}=7.578125<7.65;\ 1\\
|
||||
$$
|
||||
Final result is `11000011`
|
||||
|
||||
Bit-depth of the microcontroller creates the resolution.
|
||||
|
24
3-March/3-4_Notes.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Exam Review
|
||||
|
||||
## PWM
|
||||
|
||||
### Timer0/2
|
||||
|
||||
Modes 3 and 7 are FastPWM.
|
||||
|
||||
Mode 3: 8 bit timer. 2 possible independent triggers, on `OCRxA` and `OCRxB`
|
||||
|
||||
Mode 7: reset on `OCRxA`. trigger on `OCRxB`
|
||||
|
||||
### Timer1
|
||||
|
||||
Mode 5: 8 bit timer. 2 possible independent triggers, on `OCR1A` and `OCR1B`
|
||||
|
||||
Mode 6: 9 bit timer. 2 possible independent triggers, on `OCR1A` and `OCR1B`
|
||||
|
||||
Mode 7: 10 bit timer. 2 possible independent triggers, on `OCR1A` and `OCR1B`
|
||||
|
||||
Mode 14: reset on `ICR1`. 2 possible independent triggers, on `OCR1A` and `OCR1B`
|
||||
|
||||
Mode 15: reset on `OCR1A`. Trigger on `OCR1B`
|
||||
|
BIN
3-March/L20_IR_Sensing_VOPP.pptx
Normal file
BIN
3-March/L21_Bluetooth_VOPP.pptx
Normal file
32
3-March/lecture17Worksheet.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
1. Go to MyCourses and click on Zoom. Join the meeting and say "hi". :white_check_mark:
|
||||
|
||||
2. Indicate which of the following quantities are analog and which are digital.
|
||||
|
||||
1. ten position switch
|
||||
analog/==digital==
|
||||
|
||||
2. current flowing from an electrical circuit
|
||||
==analog==/digital
|
||||
|
||||
3. Temperature of a room
|
||||
==analog==/digital
|
||||
|
||||
4. sand grains on a beach
|
||||
analog/==digital==
|
||||
|
||||
5. automobile fuel gauge
|
||||
==analog/digital==[^1]
|
||||
|
||||
[^1]:While the gauge that we see is often analog, it can also be digital. Furthermore, there is some level of data lost between the pseudo-analog gauge we see in the drivers seat and the actual measurement in the tank, due to the information being fed through the computer of the car first.
|
||||
|
||||
3. The process of converting an analog signal to a digital signal is called digitizing. How can the accuracy of the digital representation of an analog signal be increased?
|
||||
One way is increasing the sample rate. The other is to make your high and low limits smaller, leaving your more possible datapoints in the middle.
|
||||
4. The process used by the ADC in the ATMega328 is called *Successive Approximation ADC*
|
||||
5. Refer to slide 32 and take out a calculator. The formula for resolution is $V_{ref}-V_{min}\over2^n$. Do that calculation on your calculator and don't round off. Now multiply that number by 195. What do you get?
|
||||
7.605V
|
||||
Does it look familiar?
|
||||
Its almost the same as the value we're measuring.
|
||||
6. Now assume an ADC with a 10-bit resolution and a 5V $V_{ref}$. What is the resolution?
|
||||
0.0048828125
|
||||
If the ADC returns `0111000101` what is the voltage value it is reading?
|
||||
2.2119140625V
|
BIN
3-March/lecture17Worksheet.pdf
Normal file
76
3-March/lecture18Worksheet.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
There are 3 registers associated with ADC:
|
||||
|
||||
# `ADMUX`
|
||||
|
||||
1. Set the `ADLAR` bit to left or right justify the results. You would justify if you only need 8 bits of precision and just use the `ADCH` byte. When you right justify, use both the `ADCH` and `ADCL` bytes for 10 bits of precision.
|
||||
How would the following registers be filled by the ADC hardware when the result of the conversion is `1110001100`?
|
||||
|
||||
Left Aligned: `ADLAR=0`
|
||||
|
||||
| b~15~ | b~14~ | b~13~ | b~12~ | b~11~ | b~10~ | b~9~ | b~8~ | b~7~ | b~6~ | b~5~ | b~4~ | b~3~ | b~2~ | b~1~ | b~0~ |
|
||||
| ----- | ----- | ----- | ----- | ----- | ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
|
||||
|
||||
Right Aligned: `ADLAR=1`
|
||||
| b~15~ | b~14~ | b~13~ | b~12~ | b~11~ | b~10~ | b~9~ | b~8~ | b~7~ | b~6~ | b~5~ | b~4~ | b~3~ | b~2~ | b~1~ | b~0~ |
|
||||
| ----- | ----- | ----- | ----- | ----- | ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
|
||||
2. Set `REFS1` and `REFS0` to set your reference voltage. If you choose `00` for these bits you must connect a voltage source to the `AREF` pin externally.
|
||||
Write the instruction(s) that initializes the `ADMUX` register so that the reference voltage is `AVCC` (On an Arduino platform, `AVCC` is internally connected to 5V `VCC`)
|
||||
|
||||
```c
|
||||
ADMUX |= 0x40;
|
||||
```
|
||||
|
||||
3. Choose your analog source pin (from port C) and enable it using the `MUX3`-`MUX0` bits.
|
||||
Write the instruction(s) to select pin PC2 as the analog source pin to the ADC.
|
||||
|
||||
```c
|
||||
ADMUX |= 0x02;
|
||||
```
|
||||
|
||||
|
||||
|
||||
# `ADCSRA`
|
||||
|
||||
1. Choose a clock divider given the frequency of your system clock. Remember that ADCs work best between 50-200kHz. The Arduino clock frequency is 16MHz but other systems may be different. Prescale is set with `ADPS2`-`ADPS0` bits.
|
||||
What are the only clock divider options we can use to ensure a frequency between 50-200kHz range on an Arduino platform?
|
||||
`111` and `110`, or 64 and 128
|
||||
|
||||
2. Do you want to trigger an interrupt when the conversion is complete? If so, set the `ADIE` bit. If you trigger an interrupt, you will also need an ISR.
|
||||
What is the name of the interrupt vector for the ADC interrupt?
|
||||
`ADC_vect`
|
||||
|
||||
3. If you don't use an interrupt, you can poll the `ADIF` bit to know when the conversion is complete. It will go high.
|
||||
Write the code for a While loop that waits for the `ADIF` bit to go high.
|
||||
|
||||
```c
|
||||
while(ADCSRA & 0x10){}
|
||||
```
|
||||
|
||||
4. Do you want to start the conversion under program control, or upon the occurrence of another event (or free running mode)? Set the `ADATE` bit accordingly- 0 for program controlled conversions, and 1 for free-running mode and event-driven conversions.
|
||||
If you are initializing the conversion on the occurrence of another event, what other register needs to be initialized in `setup()`?
|
||||
The interrupt that corresponds with the other event. (i.e. The pin-change interrupt or the timer interrupt.)
|
||||
|
||||
5. Turn on the ADC circuitry with the `ADEN` bit.
|
||||
|
||||
6. Finally, use the `ADSC` to start the conversions. In free running mode, do this at the end of setup. In program controlled conversions, it gets set in the main loop at the time a conversion is needed.
|
||||
If you are not in free-running mode, why should you wait to set the `ADSC` bit in `loop()`?
|
||||
|
||||
If you don't, then it will only run the conversion once, then stop. Putting it in the loop ensures it runs every instance that you want it to.
|
||||
|
||||
# `ADCSRA`
|
||||
|
||||
1. If you want free-running mode or an event-triggered interrupt, use the `ADTS2`-`ADTS0` bits to set that.
|
||||
Write the instructions to initialize the ADC to start a conversion on a `TIMER1` overflow interrupt.
|
||||
|
||||
```c
|
||||
void setup(){
|
||||
//assumed timer1 setup here
|
||||
//other ADC setup not established in this question
|
||||
ADCSRB |= 0x07;
|
||||
}
|
||||
```
|
||||
|
||||
|
BIN
3-March/lecture18Worksheet.pdf
Normal file
56
3-March/lecture19Worksheet.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
1. Using the ADC notes and the ATmega328 datasheet, write the code for the following:
|
||||
- assume an arduino set up with a potentiometer on PC3
|
||||
- initialize the pin
|
||||
- in `setup()` function, initialize the ADC by writing to its 3 registers. It should be in free-running mode.
|
||||
- In `loop()` print the ADC value to the serial terminal each time a conversion completes, you can use polling to determine when the conversion is completed.
|
||||
|
||||
```c
|
||||
void setup()
|
||||
{
|
||||
DDRC |= 0x04;
|
||||
ADMUX = 0x43;
|
||||
ADCSRA = 0xAD;
|
||||
ADCSRA |= 0x40;
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(1){}
|
||||
}
|
||||
ISR(ADC_vect)
|
||||
{
|
||||
byte tempVar = ADCL;
|
||||
Serial.println(tempVar);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
2. Starting from the above code, write a second program that reads the potentiometer every one second (use a timer interrupt as a trigger)
|
||||
|
||||
```c
|
||||
void setup()
|
||||
{
|
||||
DDRC |= 0x04;
|
||||
ADMUX = 0x43;
|
||||
ADCSRA = 0xAD;
|
||||
TCCR1A = 0x02;
|
||||
TCCR1B = 0x1B;
|
||||
ICR1 = 62499;
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(1){}
|
||||
}
|
||||
ISR(TIMER1_OVF_vect)
|
||||
{
|
||||
ADCSRA |= 0x40;
|
||||
while(ADCSRA & 0x10){}
|
||||
byte tempVar = ADCL;
|
||||
Serial.println(tempVar);
|
||||
}
|
||||
```
|
||||
|
BIN
3-March/lecture19Worksheet.pdf
Normal file
45
3-March/lecture20Worksheet.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
# Lecture 20 Worksheet
|
||||
|
||||
1. BPS stands for Band Pass Filter when referring to carrier frequencies.
|
||||
==True==/False
|
||||
2. A preamplifier makes a recieved signal smaller so it is easier to read.
|
||||
True/==False==
|
||||
3. Blocking out interfering signals is the main goal of IR modulation
|
||||
True/==False==
|
||||
4. Infrared waves are not visible to humans.
|
||||
==True==/False
|
||||
|
||||
1. Which of the following generates/emits IR waves? Highlight all that apply.
|
||||
1. Picture Frame
|
||||
2. ==Cats==
|
||||
3. ==Sun==
|
||||
4. ==Soldering Iron==
|
||||
5. Coat Hanger
|
||||
2. Which directive is used to import a header file into your C code so you may use a library?
|
||||
1. #define
|
||||
2. #ifdef
|
||||
3. ==#include==
|
||||
4. #library
|
||||
3. At what frequency are you modulating the transmission from your lab kit IR remote?
|
||||
38kHz
|
||||
4. Write a nested if statement required to detect a 1 or a 2 from your lab kit remote. If a 1 is recieved, write a 1 to a variable named `read_data`. If it is a 2, write a 2 to `read_data`. If any other number is recieved, write a 0 to `read_data`.
|
||||
|
||||
```c++
|
||||
#include <IRremote.h>
|
||||
#define IR_RECV_PIN A3
|
||||
IRrecv irrecv(IR_RECV_PIN);
|
||||
decode_results IR_command_recieved;
|
||||
int read_data;
|
||||
void setup(){
|
||||
|
||||
}
|
||||
|
||||
void loop(){
|
||||
if(irrecv.decode(&IR_command_received)){
|
||||
if (IR_command_recieved.value == ONE) read_data = 1;
|
||||
else if (IR_command_recieved.value == TWO) read_data = 2;
|
||||
else read_data = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
BIN
3-March/lecture20Worksheet.pdf
Normal file
46
3-March/lecture21Worksheet.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
1. List reasons why Bluetooth is a popular wireless communication protocol.
|
||||
Small, low cost, low power, widely implemented.
|
||||
|
||||
2. List limitations of Bluetooth.
|
||||
Prevalence creates interference amongst nets, its on the same frequency as a lot of proprietary communication standards leading to further interference, short communcation range, and slow transfer rate.
|
||||
|
||||
3. It is possible to communicate via Bluetooth in an adjacent classroom.
|
||||
True/==False==[^1]
|
||||
|
||||
[^1]: It is possible, but isn't completely true, as the connection may drop out when using the farthest points of the classrooms
|
||||
|
||||
4. A Bluetooth Piconet can have up to how many active peripherals?
|
||||
|
||||
1. 63
|
||||
2. 31
|
||||
3. 15
|
||||
4. ==7==
|
||||
|
||||
5. Bluetooth can support simultaneous connections. The devices don't interfere with each other due to:
|
||||
|
||||
1. ==Spread-spectrum frequency hopping==
|
||||
2. radio shielding in each device
|
||||
3. dedicated frequencies for each stream of data
|
||||
4. none of the above
|
||||
|
||||
6. Bluetooth devices change frequencies
|
||||
|
||||
1. five times per second
|
||||
2. 100 times per second
|
||||
3. ==1600 times per second==
|
||||
4. 3200 times per second
|
||||
|
||||
7. You can change the address of a Bluetooth device.
|
||||
True/==False==
|
||||
|
||||
8. Which of the following transfer protocols are supported by Bluetooth
|
||||
|
||||
1. ==AVRCP==
|
||||
2. I2C
|
||||
3. ==GAVDP==
|
||||
4. ==RFCOMM==
|
||||
|
||||
9. Which transfer protocol is used by the Bluetooth module in our lab kit?
|
||||
RFCOMM
|
||||
|
||||
10. With your Bluetooth devices in ==discover== mode, other bleutooth devices can find and make contact with you.
|
BIN
3-March/lecture21Worksheet.pdf
Normal file
BIN
4-April/L22_EEPROM_VOPP.pptx
Normal file
14
4-April/examSetup.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
Go to class section on micros, primarily focusing on I2C and new things
|
||||
|
||||
Look at exam 3 topics
|
||||
|
||||
The exam is in Quizzes at the normal class time
|
||||
|
||||
1 hour to complete exam
|
||||
|
||||
When you complete exam, the final exam grade may not be the exam grade you get
|
||||
|
||||
Same question set as normal
|
||||
|
||||
Coding will be read individually. Unknown length on coding. I2C coding and EEPROM coding questions will be able to use the functions given in lecture (i2cstart, eepromwrite)
|
||||
|
9
4-April/lecture22Worksheet.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
1. How does EEPROM differ from EPROM?
|
||||
2. Think of a system with an embedded processor. What data do you think is stored in EEPROM? Remember that the data can be over written, but is saved upon power loss.
|
||||
3. There are ==8== bits in a byte. As such, when we say that EEPROM is 1kbyte, it indicates that there are ==1000== locations each containing ==8== bits.
|
||||
4. Why is the EEPROM address register, EEAR 16 bits in length?
|
||||
5. Why are there 3 different options for erasing and writing? Why would you use one over the other?
|
||||
6. What triggers the EEPROM interrupt? Why do you need to be careful when enabling the EEPROM interrupt?
|
||||
7. In the code on slide 18, why are the interrupts turned off then back on again?
|
||||
8. Write the lines of code necessary to retrieve the data stored in EEPROM location 255, invert it, and store it to location 511. You may call the read and write functions provided in the lecture.
|
||||
|
BIN
ATmega328-328P_Datasheet_2016.pdf
Executable file
BIN
Homework/TeammateEval1.docx
Normal file
BIN
Homework/TeammateEval2.docx
Normal file
BIN
Homework/homework2.pdf
Normal file
BIN
Homework/homework3.pdf
Normal file
BIN
Homework/homework4.pdf
Normal file
BIN
Homework/homework5.pdf
Normal file
BIN
Homework/homework7.pdf
Normal file
BIN
Homework/hw2.assets/hw2q2.png
Normal file
After Width: | Height: | Size: 24 KiB |
120
Homework/hw2.md
Normal file
|
@ -0,0 +1,120 @@
|
|||
# Skyler MacDougall
|
||||
|
||||
## Homework 2: Due 1/29/2020
|
||||
|
||||
1. Rewrite Lab 1, page 15, using C and register writes. ArduinoC is allowed for the use of Serial outputs and delays.
|
||||
|
||||
```c
|
||||
//Lab_1_hello_arduino
|
||||
//#define LED_PIN 13
|
||||
char inChar;
|
||||
boolean isFreshInChar;
|
||||
|
||||
void setup() {
|
||||
DDRB |= 0x20; //pinMode(LED_PIN , OUTPUT);
|
||||
PORTB &= 0xDF; //digitalWrite(LED_PIN , LOW);
|
||||
|
||||
// Set serial monitor console termination for 'No line ending'
|
||||
Serial.begin(9600);
|
||||
Serial.println("Lab 1: hello arduino v0.3\n");
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
isFreshInChar = false;
|
||||
if (Serial.available()) {
|
||||
inChar = Serial.read();
|
||||
Serial.print("Serial input detected: ");
|
||||
Serial.println(inChar);
|
||||
isFreshInChar = true;
|
||||
}
|
||||
|
||||
if (inChar == 'n') PORTB |= 0x20; //digitalWrite(LED_PIN , HIGH); oN
|
||||
if (inChar == 'f') PORTB &= 0xDF; //digitalWrite(LED_PIN , LOW); oFf
|
||||
|
||||
if (inChar == 'b') { // blink with 25% duty cycle
|
||||
PORTB |= 0x20; //digitalWrite(LED_PIN , HIGH);
|
||||
delay(250);
|
||||
PORTB &= 0xDF; //digitalWrite(LED_PIN , LOW);
|
||||
delay(750);
|
||||
}
|
||||
|
||||
// Discover 't' persistence bug by observing high rate LED blink
|
||||
if (inChar == 't') { // toggle
|
||||
//digitalWrite(LED_PIN , !digitalRead(LED_PIN ));
|
||||
if (PINB & 0x20){
|
||||
PORTB &= 0xDF;
|
||||
}
|
||||
else{
|
||||
PORTB |= 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
// Add state change detection to get proper toggle action.
|
||||
if (inChar == 'T') { // toggle
|
||||
if (isFreshInChar){//digitalWrite(LED_PIN , !digitalRead(LED_PIN ));
|
||||
if (PINB & 0x20){
|
||||
PORTB &= 0xDF;
|
||||
}
|
||||
else{
|
||||
PORTB |= 0x20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // loop()
|
||||
```
|
||||
|
||||
2. Assuming the below, write a program using register reads and writes, read the state of the switches and turn the LEDs on if the switches are closed.
|
||||

|
||||
|
||||
```c
|
||||
void setup(){
|
||||
DDRB = 0xF0;
|
||||
PORTB = 0x0F;
|
||||
}
|
||||
|
||||
void loop(){
|
||||
//LED0
|
||||
if(PINB & 0x01){
|
||||
PORTB |= 0x10;
|
||||
}
|
||||
else{
|
||||
PORTB &= 0xEF;
|
||||
}
|
||||
//LED1
|
||||
if(PINB & 0x02){
|
||||
PORTB |= 0x20;
|
||||
}
|
||||
else{
|
||||
PORTB &= 0xCF;
|
||||
}
|
||||
//LED2
|
||||
if(PINB & 0x04){
|
||||
PORTB |= 0x40;
|
||||
}
|
||||
else{
|
||||
PORTB &= 0xBF;
|
||||
}
|
||||
//LED3
|
||||
if(PINB & 0x08){
|
||||
PORTB |= 0x80;
|
||||
}
|
||||
else{
|
||||
PORTB &= 0x7F;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Explain the steps necessary when changing the state of a port from input to output, or vice versa.
|
||||
|
||||
```c
|
||||
//The following is a step by step for how to go from in to out.
|
||||
PORTD = 0x00;
|
||||
DDRD = 0xFF;
|
||||
//The following is a step by step for how to go from out to in
|
||||
DDRD = 0x00;
|
||||
PORTD = 0xFF;
|
||||
```
|
||||
|
||||
The steps stated above are for full ports. The process is similar for single pin assignment.
|
BIN
Homework/hw2.pdf
Normal file
BIN
Homework/hw2q2.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
Homework/hw3.assets/stateMachineCar.jpg
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
Homework/hw3.assets/stateMachineLight.jpg
Normal file
After Width: | Height: | Size: 1.3 MiB |
187
Homework/hw3.md
Normal file
|
@ -0,0 +1,187 @@
|
|||
3.
|
||||
|
||||

|
||||
|
||||
```c
|
||||
enum{HGFR, HYFR, HRFR, HRFG, HRFY, HRFRR, HRRFRR};
|
||||
bool detect = false;
|
||||
int state = HRFRR, prevState = !state;
|
||||
float stateTimer = 0;
|
||||
boolean isNewState;
|
||||
void setup(){
|
||||
DDRD |= 0xFC; //setting light pins to output
|
||||
DDRB &= ~(0x01); //set detect pin to input
|
||||
PORTB |= 0x01; //turn on detect pin pullup
|
||||
}
|
||||
|
||||
void loop(){
|
||||
detect = (PINB & 0x01);
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
switch(state){
|
||||
case HGFR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x80);
|
||||
PORTD |= 0x30;
|
||||
}
|
||||
if(detect) state = HYFR;
|
||||
break;
|
||||
|
||||
case HYFR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x20);
|
||||
PORTD |= 0x40;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HRFR;
|
||||
break;
|
||||
|
||||
case HRFR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x40);
|
||||
PORTD |= 0x80;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HRFR;
|
||||
break;
|
||||
|
||||
case HRFG:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x10);
|
||||
PORTD |= 0x04;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if((stateTimer >= 40000) || !(detect)) state = HRFY;
|
||||
break;
|
||||
|
||||
case HRFY:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x04);
|
||||
PORTD |= 0x08;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HRFRR;
|
||||
break;
|
||||
|
||||
case HRFRR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x08);
|
||||
PORTD |= 0x10;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HGFR;
|
||||
break;
|
||||
|
||||
case HRRFRR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x08);
|
||||
PORTD |= 0x10;
|
||||
stateTimer=0;
|
||||
}
|
||||
break;
|
||||
|
||||
default: state = HRRFRR;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
4.
|
||||
|
||||

|
||||
|
||||
```c
|
||||
enum{fwd, backr, backl, turnr, turnl, stop};
|
||||
bool rs = false, ls = false;
|
||||
int state = fwd, prevState = !fwd;
|
||||
int stateTimer = 0;
|
||||
#define forward 0xC0
|
||||
#define rightTurn 0x40
|
||||
#define leftTurn 0x80
|
||||
boolean isNewState;
|
||||
void setup(){
|
||||
DDRD |= 0xC0; DDRD &= ~(0x03); //setting input/output pins
|
||||
PORTD |= 0x03; //setting pushbutton pullups
|
||||
}
|
||||
|
||||
void loop(){
|
||||
rs = !(PIND & 0x02);
|
||||
ls = !(PIND & 0x01);
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
switch(state){
|
||||
case fwd:
|
||||
if(isNewState){
|
||||
PORTD |= forward;
|
||||
}
|
||||
if(rs) state = backr;
|
||||
else if(ls) state = backl;
|
||||
break;
|
||||
|
||||
case backr:
|
||||
if(isNewState){
|
||||
PORTD &= ~(forward);
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if (stateTimer >= 500) state = turnr;
|
||||
break;
|
||||
|
||||
case turnr:
|
||||
if(isNewState){
|
||||
PORTD |= rightTurn;
|
||||
}
|
||||
if (stateTimer >= 500) state = fwd;
|
||||
break;
|
||||
|
||||
case backl:
|
||||
if(isNewState){
|
||||
PORTD &= ~(forward);
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if (stateTimer >= 500) state = turnl;
|
||||
break;
|
||||
|
||||
case turnl:
|
||||
if(isNewState){
|
||||
PORTD |= leftTurn;
|
||||
}
|
||||
if (stateTimer >= 500) state = fwd;
|
||||
break;
|
||||
|
||||
case stop:
|
||||
if(isNewState){
|
||||
PORTD &= ~(forward);
|
||||
}
|
||||
break;
|
||||
|
||||
default: state = stop;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
```
|
||||
|
BIN
Homework/hw3.pdf
Normal file
73
Homework/hw3q1/hw3q1.ino
Normal file
|
@ -0,0 +1,73 @@
|
|||
enum{fwd, backr, backl, turnr, turnl, stop};
|
||||
bool rs = false, ls = false;
|
||||
int state = fwd, prevState = !fwd;
|
||||
int stateTimer = 0;
|
||||
#define forward 0xC0
|
||||
#define rightTurn 0x40
|
||||
#define leftTurn 0x80
|
||||
boolean isNewState;
|
||||
void setup(){
|
||||
DDRD |= 0xC0; DDRD &= ~(0x03); //setting input/output pins
|
||||
PORTD |= 0x03; //setting pushbutton pullups
|
||||
}
|
||||
|
||||
void loop(){
|
||||
rs = !(PIND & 0x02);
|
||||
ls = !(PIND & 0x01);
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
switch(state){
|
||||
case fwd:
|
||||
if(isNewState){
|
||||
PORTD |= forward;
|
||||
}
|
||||
if(rs) state = backr;
|
||||
else if(ls) state = backl;
|
||||
break;
|
||||
|
||||
case backr:
|
||||
if(isNewState){
|
||||
PORTD &= ~(forward);
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if (stateTimer >= 500) state = turnr;
|
||||
break;
|
||||
|
||||
case turnr:
|
||||
if(isNewState){
|
||||
PORTD |= rightTurn;
|
||||
}
|
||||
if (stateTimer >= 500) state = fwd;
|
||||
break;
|
||||
|
||||
case backl:
|
||||
if(isNewState){
|
||||
PORTD &= ~(forward);
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if (stateTimer >= 500) state = turnl;
|
||||
break;
|
||||
|
||||
case turnl:
|
||||
if(isNewState){
|
||||
PORTD |= leftTurn;
|
||||
}
|
||||
if (stateTimer >= 500) state = fwd;
|
||||
break;
|
||||
|
||||
case stop:
|
||||
if(isNewState){
|
||||
PORTD &= ~(forward);
|
||||
}
|
||||
break;
|
||||
|
||||
default: state = stop;
|
||||
}
|
||||
delay(1);
|
||||
}
|
96
Homework/hw3q2/hw3q2.ino
Normal file
|
@ -0,0 +1,96 @@
|
|||
enum{HGFR, HYFR, HRFR, HRFG, HRFY, HRFRR, HRRFRR};
|
||||
bool detect = false;
|
||||
int state = HRFRR, prevState = !state;
|
||||
float stateTimer = 0;
|
||||
boolean isNewState;
|
||||
void setup(){
|
||||
DDRD |= 0xFC; //setting light pins to output
|
||||
DDRB &= ~(0x01); //set detect pin to input
|
||||
PORTB |= 0x01; //turn on detect pin pullup
|
||||
}
|
||||
|
||||
void loop(){
|
||||
detect = (PINB & 0x01);
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
switch(state){
|
||||
case HGFR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x80);
|
||||
PORTD |= 0x30;
|
||||
}
|
||||
if(detect) state = HYFR;
|
||||
break;
|
||||
|
||||
case HYFR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x20);
|
||||
PORTD |= 0x40;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HRFR;
|
||||
break;
|
||||
|
||||
case HRFR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x40);
|
||||
PORTD |= 0x80;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HRFR;
|
||||
break;
|
||||
|
||||
case HRFG:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x10);
|
||||
PORTD |= 0x04;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if((stateTimer >= 40000) || !(detect)) state = HRFY;
|
||||
break;
|
||||
|
||||
case HRFY:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x04);
|
||||
PORTD |= 0x08;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HRFRR;
|
||||
break;
|
||||
|
||||
case HRFRR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x08);
|
||||
PORTD |= 0x10;
|
||||
stateTimer=0;
|
||||
}
|
||||
if(!(isNewState)){
|
||||
stateTimer++;
|
||||
}
|
||||
if(stateTimer >= 5000)state = HGFR;
|
||||
break;
|
||||
|
||||
case HRRFRR:
|
||||
if(isNewState){
|
||||
PORTD &= ~(0x08);
|
||||
PORTD |= 0x10;
|
||||
stateTimer=0;
|
||||
}
|
||||
break;
|
||||
|
||||
default: state = HRRFRR;
|
||||
}
|
||||
delay(1);
|
||||
}
|
BIN
Homework/hw4.assets/music.jpg
Normal file
After Width: | Height: | Size: 58 KiB |
263
Homework/hw4.md
Normal file
|
@ -0,0 +1,263 @@
|
|||
# Skyler MacDougall, Matthew Gerace
|
||||
|
||||
# Homework 4: Due 2/12/2020
|
||||
|
||||
1. There are 25 notes of the musical scale. They are each produced by a square wave with the frequency as defined by the following formula:
|
||||
$$
|
||||
f_{note}=440\times 2^{P\over12}\\
|
||||
-12\le P\le 12
|
||||
$$
|
||||
The period of the square wave is as follows:
|
||||
$$
|
||||
T_{note}={1\over f_{note}}\\
|
||||
hint:\ (OCR1A+1)={T_{note}\over 2}={16MHz\over2\times f_{note}}
|
||||
$$
|
||||
1. For the 25 notes where $220\le f_{note}\le 880$, determine the `OCR1A` values needed to output the square wave of each note using Timer1 in CTC mode.
|
||||
|
||||
2. Open another program and use `#define` to create 25 constants for the results of part 1. Also create time delay constants.
|
||||
|
||||
3. In the initialization section setup Timer1 to create a square wave.
|
||||
|
||||
4. Create a function called `playNote()`.
|
||||
|
||||
1. It takes in an integer representing the max count for a given note and assigns that value to the `OCR1A` register.
|
||||
2. It also takes in a delay constant to hold the note for a given amount of time.
|
||||
3. it must then turn off CTC mode and `delay(50)` to put a break between notes.
|
||||
|
||||
5. In the main loop call the function with different notes and delays in between. You can look up simple songs on the internet and experiment with delays to actually play a song.
|
||||
|
||||
6. Use the speaker in your lab kit and drive one pin with the waveform output and the other to ground.
|
||||
|
||||

|
||||
|
||||
```c
|
||||
//Note-name/constant conversion
|
||||
#define LA 36363
|
||||
#define LAS 34323
|
||||
#define LB 32396
|
||||
#define LC 30578
|
||||
#define LCS 28861
|
||||
#define LD 27242
|
||||
#define LDS 25713
|
||||
#define LE 24270
|
||||
#define LF 22908
|
||||
#define LFS 21622
|
||||
#define LG 20408
|
||||
#define LGS 19263
|
||||
#define MA 18182
|
||||
#define MAS 17161
|
||||
#define MB 16198
|
||||
#define MC 15289
|
||||
#define MCS 14430
|
||||
#define MD 13620
|
||||
#define MDS 12856
|
||||
#define ME 12135
|
||||
#define MF 11454
|
||||
#define MFS 10811
|
||||
#define MG 10204
|
||||
#define MGS 9631
|
||||
#define HA 9091
|
||||
|
||||
//Note Length definitions
|
||||
#define QUARTER 400
|
||||
#define EIGHTH 200
|
||||
#define DOTQUARTER 600
|
||||
#define HALF 800
|
||||
|
||||
void setup(){
|
||||
TCCR1A=0x40;
|
||||
TCCR1B=0x09;
|
||||
TCCR1C=0;
|
||||
TCNT1=0;
|
||||
DDRB|=0x02;
|
||||
}
|
||||
|
||||
void playNote(int note, int time){
|
||||
OCR1A = note;
|
||||
delay(time);
|
||||
OCR1A = 0;
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MD, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LD, QUARTER);
|
||||
playNote(LD, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MC, QUARTER);
|
||||
playNote(MD, DOTQUARTER);
|
||||
playNote(MD, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LG, HALF);
|
||||
playNote(MD, HALF);
|
||||
playNote(MB, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, DOTQUARTER);
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LG, HALF);
|
||||
playNote(LG, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, HALF);
|
||||
delay(1000);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
2. Use Timer1 in normal mode to create an output wave that has the following properties:
|
||||
$$
|
||||
f=1Hz\\
|
||||
duty\ cycle=25\%
|
||||
$$
|
||||
Assume that this output is driving an LED that will cause it to blink. You can use a 2-state state machine.
|
||||
(Hint: Use `TOV1` as the exit condition for the states. you will need a prescaler.)
|
||||
|
||||
***DO NOT USE PWM.***
|
||||
|
||||
```c
|
||||
#define OVERFLAG 0x02
|
||||
#define OVERFLOW 0x01
|
||||
#define LEDHIGH 0x02
|
||||
#define LEDLOW 0xFD
|
||||
enum{LED_on, LED_off, stop};
|
||||
int state = LED_on, prevState = !LED_on;
|
||||
int stateTimer = 0;
|
||||
boolean isNewState;
|
||||
void setup(){
|
||||
TCCR1A = 0x80;
|
||||
TCCR1B = 0x04;
|
||||
TCCR1C = 0;
|
||||
TCNT1 = 65536 - 23437;
|
||||
OCR1A = 24520;
|
||||
DDRB |= 0x02;
|
||||
PORTB &= ~(0x02);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
switch(state){
|
||||
case LED_on:
|
||||
if(isNewState)
|
||||
{
|
||||
PORTB |= LEDHIGH;
|
||||
TIFR |= OVERFLOW;//Flag reset
|
||||
}
|
||||
|
||||
if(TIFR & OVERFLAG) state = LED_off;
|
||||
break;
|
||||
|
||||
case LED_off:
|
||||
if(isNewState)
|
||||
{
|
||||
PORTB &= LEDLOW;
|
||||
TIFR |= OVERFLAG; //Flag reset
|
||||
}
|
||||
|
||||
if(TIFR & OVERFLOW) state = LED_on;
|
||||
break;
|
||||
|
||||
case stop:
|
||||
PORTB |= 0x02;
|
||||
break;
|
||||
default: state = stop;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
3. For each group member, discuss the feasibility of the invention. Is it feasible? Why or why not? List the I/O devices that each invention would require.
|
||||
|
||||
1. Skyler MacDougall
|
||||
|
||||
one-way switch
|
||||
|
||||
- 2 servos
|
||||
- 3 pins each
|
||||
- 1 servo to move the arm
|
||||
- 1 servo to adjust the y-axis to flip the switch
|
||||
- 1 switch
|
||||
- 1 pin
|
||||
|
||||
2. Matthew Gerace
|
||||
|
||||
Pool measurement device
|
||||
|
||||
Screen for temp and pH readout
|
||||
|
||||
I/O devices:
|
||||
|
||||
- pH sensor
|
||||
- 2 pins
|
||||
- thermocouple
|
||||
- 2 pins
|
||||
- switch
|
||||
- 1 pin
|
||||
- for changing between pH and temp
|
||||
- 2 7seg displays
|
||||
- 7 pins per display
|
||||
|
BIN
Homework/hw4.pdf
Normal file
133
Homework/hw4q1/hw4q1.ino
Normal file
|
@ -0,0 +1,133 @@
|
|||
//Note-name/constant conversion
|
||||
#define LA 36363
|
||||
#define LAS 34323
|
||||
#define LB 32396
|
||||
#define LC 30578
|
||||
#define LCS 28861
|
||||
#define LD 27242
|
||||
#define LDS 25713
|
||||
#define LE 24270
|
||||
#define LF 22908
|
||||
#define LFS 21622
|
||||
#define LG 20408
|
||||
#define LGS 19263
|
||||
#define MA 18182
|
||||
#define MAS 17161
|
||||
#define MB 16198
|
||||
#define MC 15289
|
||||
#define MCS 14430
|
||||
#define MD 13620
|
||||
#define MDS 12856
|
||||
#define ME 12135
|
||||
#define MF 11454
|
||||
#define MFS 10811
|
||||
#define MG 10204
|
||||
#define MGS 9631
|
||||
#define HA 9091
|
||||
|
||||
//Note Length definitions
|
||||
#define QUARTER 400
|
||||
#define EIGHTH 200
|
||||
#define DOTQUARTER 600
|
||||
#define HALF 800
|
||||
|
||||
void setup(){
|
||||
TCCR1A=0x40;
|
||||
TCCR1B=0x09;
|
||||
TCCR1C=0;
|
||||
TCNT1=0;
|
||||
DDRB|=0x02;
|
||||
}
|
||||
|
||||
void playNote(int note, int time){
|
||||
OCR1A = note;
|
||||
delay(time);
|
||||
OCR1A = 0;
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MD, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LD, QUARTER);
|
||||
playNote(LD, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MC, QUARTER);
|
||||
playNote(MD, DOTQUARTER);
|
||||
playNote(MD, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LG, HALF);
|
||||
playNote(MD, HALF);
|
||||
playNote(MB, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, DOTQUARTER);
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LG, HALF);
|
||||
playNote(LG, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, HALF);
|
||||
delay(1000);
|
||||
}
|
313
Homework/hw5.md
Normal file
|
@ -0,0 +1,313 @@
|
|||
# Skyler MacDougall, Matthew Gerace, Kaitlin Berryman
|
||||
|
||||
# Homework 5: Due 2/19/2020
|
||||
|
||||
1. Create a reaction timer.
|
||||
|
||||
- After a random amount of time, the yellow LED turns on, the timer starts.
|
||||
- If the user presses the button before the timer times out, the green LED goes on, and the yellow turns off.
|
||||
- If the timer times out, the red LED goes on, and the yellow goes off.
|
||||
- Use `delay();` and `random();` for the delay before the yellow light.
|
||||
- check for the button push in the main program loop and use the timer interrupt to know that time is up
|
||||
- start with setting the timer to 1/2 second and shorten it from there.
|
||||
- be sure to disable the interrupt as soon as the user presses the button.
|
||||
|
||||
```c
|
||||
// Homework 5, Problem 1
|
||||
// digital pins D5, D6, D7, D8
|
||||
|
||||
void setup()
|
||||
{
|
||||
DDRD |= 0x20; // make PD5 an output -- green
|
||||
DDRD |= 0x40; // make PD6 an output -- yellow
|
||||
DDRD |= 0x80; // make PD7 an output -- red
|
||||
DDRB |= 0x01; // make PB0 an input -- switch
|
||||
|
||||
PORTD &= 0xDF; // turn PD5 output off
|
||||
PORTD &= 0xBF; // turn PD6 output off
|
||||
PORTD &= 0x7F; // turn PD7 output off
|
||||
|
||||
// CTC mode timer setups
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0x0C;
|
||||
TCNT1 = 0;
|
||||
OCR1B = 31249;
|
||||
|
||||
cli(); // turn off global interrupts
|
||||
// set the intertupt flag
|
||||
TIMSK1 = 0x04;
|
||||
sei(); // turn on global interrupts
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// wait a random amount of time
|
||||
delay(random());
|
||||
|
||||
// turn the yellow LED on
|
||||
PORTD |= 0x40;
|
||||
//reset the timer
|
||||
TCNT1 = 0;
|
||||
|
||||
while(PIND & 0x40)
|
||||
{
|
||||
if (!(PINB & 0x01))
|
||||
{
|
||||
PORTD &= ~(0x40);
|
||||
PORTD |= 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
//spaced resets a set amount of time
|
||||
delay(100);
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPB_vect)
|
||||
{
|
||||
// code for servicing the interrupt
|
||||
PORTD &= ~(0x40); // turn yellow LED off
|
||||
PORTD |= 0x80; // turn red LED on
|
||||
}
|
||||
```
|
||||
|
||||
2. Rewrite lab #3 section 6 using registers and timer interrupts. Note that when interrupts are used for timers, you don’t have to implement a state timer. Remember that when a variable is updated outside the main loop you must use the volatile design so that the compile does not optimize the variable out.
|
||||
|
||||
```c
|
||||
volatile bool greenFirstRun=0, loopBack=0, redFirstRun=0, grFirstRun=0;
|
||||
#define MSEC_SAMPLE 1
|
||||
#define SW1_PIN 5
|
||||
//#define LED1_PIN 8
|
||||
//#define LED2_PIN 11
|
||||
#define LED_CLOCK_PIN 11
|
||||
#define LED_DATA_PIN 12
|
||||
#define QTR_SIG_PIN A3
|
||||
#define QTR_5V_PIN A4
|
||||
#define QTR_GND_PIN A5
|
||||
#define MSEC_SAMPLE 1
|
||||
|
||||
|
||||
enum {LED_OFF, BLINK_G_OFF, BLINK_R, BLINK_G_ON, BLINK_GR, BLINK_RATE};
|
||||
|
||||
boolean isSwPressed, prevIsSwPressed, isSwJustReleased, isSwJustPressed, isSwChange;
|
||||
volatile int state = LED_OFF;
|
||||
int prevState = !state;
|
||||
int stateTimer, adcQTR;
|
||||
boolean isNewState;
|
||||
boolean greentimer = true;
|
||||
|
||||
void setup() {
|
||||
DDRD &= ~(1 << 5); PORTD |= (1 << 5); //pinMode(SW1_PIN, INPUT_PULLUP);
|
||||
DDRB |= (1 << 3);//pinMode(LED_CLOCK_PIN, OUTPUT);
|
||||
PORTB &= ~(1 << 3);//digitalWrite(LED_CLOCK_PIN, LOW);
|
||||
DDRB |= (1 << 4); //pinMode(LED_DATA_PIN, OUTPUT);
|
||||
PORTB &= ~(1 << 4);//digitalWrite(LED_DATA_PIN, LOW);
|
||||
pinMode(QTR_SIG_PIN, INPUT);
|
||||
DDRC |= (1 << 4);//pinMode(QTR_5V_PIN, OUTPUT);
|
||||
PORTC |= (1 << 4);//digitalWrite(QTR_5V_PIN, HIGH);
|
||||
DDRC |= (1 << 5);//pinMode(QTR_GND_PIN, OUTPUT);
|
||||
PORTC &= ~(1 << 5);//digitalWrite(QTR_GND_PIN, LOW);
|
||||
|
||||
OCR1A = 15624;
|
||||
OCR1B = 31249;
|
||||
ICR1 = 0xFFFF;
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("Lab 2 Complex State Machine"));
|
||||
} // setup()
|
||||
//****************************************************************************
|
||||
void display_color_on_RGB_led(unsigned long color) {
|
||||
unsigned long bitmask=0UL; // UL unsigned long literal (forces compiler to use long data type)
|
||||
unsigned long masked_color_result=0UL;
|
||||
// digitalWrite(LED_CLOCK_PIN,LOW); //start with clock low.
|
||||
PORTB&=0b11110111;
|
||||
for(int i=23; i>=0; i--) { // clock out one data bit at a time, starting with the MSB first
|
||||
bitmask= (1UL<<i); // build bit mask. Note must use "1UL" unsigned long literal, not "1"
|
||||
masked_color_result = color & bitmask; // reveals just one bit of color at time
|
||||
boolean data_bit=!(masked_color_result==0); // this is the bit of data to be clocked out.
|
||||
// digitalWrite(LED_DATA_PIN,data_bit);
|
||||
if( data_bit ==1)
|
||||
PORTB|=0b00010000;
|
||||
else
|
||||
PORTB&=0b11101111;
|
||||
|
||||
|
||||
// digitalWrite(LED_CLOCK_PIN,HIGH);
|
||||
PORTB|=0b00001000;
|
||||
// digitalWrite(LED_CLOCK_PIN,LOW);
|
||||
PORTB&=0b11110111;
|
||||
}
|
||||
// digitalWrite(LED_CLOCK_PIN,HIGH);
|
||||
PORTB|=0b00001000;
|
||||
delay(1); // after writing data to LED driver, must hold clock line
|
||||
// high for 1 ms to latch color data in led shift register.
|
||||
}
|
||||
|
||||
void redOn(void) {
|
||||
PORTB = PORTB |(1 << 0); // sets Uno dig_8, PORTB.0, pin to 1 (HIGH)
|
||||
display_color_on_RGB_led(0xFF0000); // physical pin 14 (28 pin DIP)
|
||||
}
|
||||
//****************************************************************************
|
||||
void greenOn(void) {
|
||||
display_color_on_RGB_led(0x0000FF);
|
||||
|
||||
if (greentimer == true){
|
||||
unsigned long start_time_microseconds,end_time_microseconds;
|
||||
start_time_microseconds=micros();
|
||||
|
||||
end_time_microseconds=micros();
|
||||
Serial.print("Displaying the green color took ");
|
||||
Serial.print(end_time_microseconds-start_time_microseconds);
|
||||
Serial.println(" microseconds ");
|
||||
}
|
||||
}
|
||||
//****************************************************************************
|
||||
void allOff(void) {
|
||||
display_color_on_RGB_led(0x000000);
|
||||
}
|
||||
ISR(TIMER1_COMPA_vect){
|
||||
if(greenFirstRun){
|
||||
allOff();
|
||||
greenFirstRun = !greenFirstRun;
|
||||
}
|
||||
if(redFirstRun){
|
||||
allOff();
|
||||
redFirstRun = !redFirstRun;
|
||||
}
|
||||
if(grFirstRun){
|
||||
redOn();
|
||||
grFirstRun = !grFirstRun;
|
||||
}
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPB_vect){
|
||||
loopBack=true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
prevIsSwPressed = isSwPressed;
|
||||
isSwPressed = !(PINC & 0x20);
|
||||
isSwJustPressed = (isSwPressed && !prevIsSwPressed);
|
||||
isSwJustReleased = (!isSwPressed && prevIsSwPressed);
|
||||
isSwChange = (isSwJustReleased || isSwJustPressed);
|
||||
|
||||
isNewState = (state != prevState);
|
||||
prevState = state;
|
||||
|
||||
switch (state) {
|
||||
|
||||
case LED_OFF:
|
||||
if (isNewState) Serial.println("LED_OFF");
|
||||
allOff();
|
||||
if (isSwJustReleased)
|
||||
state = BLINK_G_ON;
|
||||
break;
|
||||
|
||||
case BLINK_G_ON:
|
||||
if (isNewState) {
|
||||
Serial.println("BLINK_G_ON");
|
||||
greenFirstRun = true;
|
||||
grFirstRun = false;
|
||||
OCR1A = 15624;
|
||||
OCR1B = 62499;
|
||||
TIMSK1 = 0x06;//Use OCR1A and OCR1B
|
||||
sei();
|
||||
greenOn();
|
||||
}
|
||||
if (loopBack){
|
||||
greenOn();
|
||||
TCNT1 = 0;
|
||||
loopBack = 0;
|
||||
greenFirstRun = true;
|
||||
}
|
||||
greentimer = false;
|
||||
if (isSwJustReleased) {
|
||||
cli();
|
||||
allOff();
|
||||
state = BLINK_R;
|
||||
}
|
||||
break;
|
||||
|
||||
case BLINK_R:
|
||||
if (isNewState) {
|
||||
TCNT1 = 0;
|
||||
greenFirstRun = false;
|
||||
redFirstRun = true;
|
||||
sei();
|
||||
redOn();
|
||||
Serial.println("BLINK_R");
|
||||
}
|
||||
if (loopBack){
|
||||
redOn();
|
||||
TCNT1 = 0;
|
||||
loopBack = false;
|
||||
redFirstRun = true;
|
||||
}
|
||||
if (isSwJustReleased) {
|
||||
allOff();
|
||||
cli();
|
||||
state = BLINK_GR;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case BLINK_GR:
|
||||
if (isNewState) {
|
||||
stateTimer = 0;
|
||||
TCNT1 = 0;
|
||||
OCR1A = 15624*2;
|
||||
grFirstRun = true;
|
||||
redFirstRun = false;
|
||||
sei();
|
||||
Serial.println("BLINK_GR");
|
||||
}
|
||||
if (loopBack){
|
||||
greenOn();
|
||||
TCNT1 = 0;
|
||||
loopBack = false;
|
||||
grFirstRun = true;
|
||||
}
|
||||
|
||||
if (isSwJustReleased) {
|
||||
allOff();
|
||||
state = LED_OFF;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: state = LED_OFF;
|
||||
} // switch (state)
|
||||
|
||||
} // loop()
|
||||
```
|
||||
|
||||
3. Servos should react to a PWM signal as shown in the homework diagram. however, a pulse width of 1ms does not always put the servo at $0^\circ$ and a pulse width of 2ms does not always put the servo at $180^\circ$. Using timer1 and a FAST PWM mode create a PWM signal to drive a servo motor. You may need to adjust the registers for pulse width to get a full $180^\circ$ of rotation. Note, you cannot just copy the code from lab 4 as that was not fast PWM mode.
|
||||
|
||||
```c
|
||||
unsigned long servoValue=0;
|
||||
//***********************************************************************************
|
||||
void setup()
|
||||
{
|
||||
pinMode(9,OUTPUT);
|
||||
Serial.begin(9600);
|
||||
TCCR1A=0xB2;
|
||||
TCCR1B=0x1B;
|
||||
ICR1=0x1387;
|
||||
|
||||
}
|
||||
//***********************************************************************************
|
||||
void loop()
|
||||
{ delay(100);
|
||||
servoValue++;
|
||||
OCR1A=144+servoValue;
|
||||
if (servoValue>=470) servoValue=0;
|
||||
}
|
||||
```
|
||||
|
||||
4. Read sections “Reset and Interrupt Handling” in the datasheet and answer the following questions:
|
||||
|
||||
1. How does microcontroller handle multiple interrupts arriving from different peripherals while an ISR is being serviced?
|
||||
|
||||
All interrupts are disabled while an ISR is being serviced.
|
||||
|
||||
2. What does microcontroller do in the 4 cycle response time to service an ISR?
|
||||
|
||||
To enter the ISR, the program counter is pushed onto the Stack during the first cycle. The next three cycles are to jump to the correct spot in memory where the interrupt routine is stored. When exiting the ISR, the program counter is popped back from the stack (two cycles), incremented twice (one cycle), and interrupts are re-enabled.
|
BIN
Homework/hw5.pdf
Normal file
304
Homework/hw6.md
Normal file
|
@ -0,0 +1,304 @@
|
|||
|
||||
|
||||
# Skyler MacDougall, Matthew Gerace
|
||||
|
||||
# Homework 6: Due 2/26/2020
|
||||
|
||||
1. Rewrite the reaction timer game program using only interrupts.
|
||||
|
||||
- A pin change interrupt on PD7 is used to start the game. When the active-low button is pressed, the yellow LED turns on after a random delay. When the LED turns on, `TCNT1=0`.
|
||||
|
||||
- `INT0` is attached to another active-low button. This is for the reaction button. if the button is pressed before a $1\over2$ second has elapsed, the green LED should light.
|
||||
|
||||
- A Timer1 interrupt should be used to count to $1\over2$ second. If $1\over2$ second passes before `INT0`, the red LED should be lit.
|
||||
|
||||
- [x] Which pins will the 3 LEDs be connected to?
|
||||
|
||||
Green = `PC0`. Yellow = `PC1`. Red = `PC2`.
|
||||
|
||||
- [x] Initialize the pins for the LEDs.
|
||||
|
||||
See line 8
|
||||
|
||||
- [x] Initialize the two interrupt pins as inputs.
|
||||
|
||||
See line 5
|
||||
|
||||
- [x] What mode should Timer1 be in to create a $1\over2$ second interrupt?
|
||||
|
||||
CTC, although PWM is also possible.
|
||||
|
||||
- [x] Initialize for `TCCR1A` and `TCCR1B` for the correct mode.
|
||||
|
||||
See lines 11 and 12.
|
||||
|
||||
- [x] Is a clock prescaler needed for $1\over2$ second interrupt?
|
||||
|
||||
Yes.
|
||||
|
||||
- [x] If so, set it up in `TCCR1B`.
|
||||
|
||||
See line 12.
|
||||
|
||||
- [x] What value goes in `OCR1A` for $1\over2$ second?
|
||||
|
||||
See line 14.
|
||||
|
||||
- [x] Enable the Timer1 interrupt.
|
||||
|
||||
See line 18.
|
||||
|
||||
- [x] Enable the pin change interrupt in the control register.
|
||||
|
||||
See line 19.
|
||||
|
||||
- [x] Enable the external interrupt in the control register.
|
||||
|
||||
See line 21.
|
||||
|
||||
- [x] Set the correct pin for the pin change interrupt in `PCMSK`
|
||||
|
||||
See line 20.
|
||||
|
||||
- [x] Set the correct pin for the external interrupt in the `EIMSK`
|
||||
|
||||
See line 22.
|
||||
|
||||
- [x] What are the names of the 3 interrupt vectors?
|
||||
|
||||
`PCINT2_vect`, `INT0_vect`, and `TIMER1_COMPA_vect`.
|
||||
|
||||
```c
|
||||
// Homework 6, Problem 1
|
||||
|
||||
void setup()
|
||||
{
|
||||
DDRD &= ~(0x82); // make PD6 and PD7 inputs -- reaction switch and start switch
|
||||
DDRC |= (1 << 0|1 << 1|1 << 2);//PC0, PC1, and PC2 outputs -- green, yellow, and red light
|
||||
|
||||
PORTC &= ~(1 << 0|1 << 1|1 << 2); //start all lights off
|
||||
|
||||
// CTC mode timer setups
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0x0C;
|
||||
TCNT1 = 0;
|
||||
OCR1A = 31249;
|
||||
|
||||
cli(); // turn off global interrupts
|
||||
// set the intertupt flag
|
||||
TIMSK1 = 4;
|
||||
PCICR = 4;
|
||||
PCMSK2 = 0x80;
|
||||
EIMSK = 1;
|
||||
EICRA = 3;
|
||||
sei(); // turn on global interrupts
|
||||
}
|
||||
|
||||
void loop(){while(1)}
|
||||
|
||||
ISR(PCINT2_vect){
|
||||
// wait a random amount of time
|
||||
delay(random());
|
||||
|
||||
// turn the yellow LED on
|
||||
PORTC |= 0x02;
|
||||
//reset the timer
|
||||
TCNT1 = 0;
|
||||
}
|
||||
|
||||
ISR(INT0_vect){
|
||||
PORTC &= ~(0x02); // turn yellow LED off
|
||||
PORTC |= 0x01; // turn red LED on
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
// code for servicing the interrupt
|
||||
PORTC &= ~(0x02); // turn yellow LED off
|
||||
PORTC |= 0x04; // turn red LED on
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
2. In the previous homework, you determined the constants that control your servo motor to rotate $180^\circ$. Starting from that point, complete the following:
|
||||
|
||||
1. Once you’ve determined the constants that will move the servo a full $180^\circ$, modify your program to create a windshield wiper controller. As you know, a windshield wiper moves smoothly across $180^\circ$. It doesn’t “snap” back to position like the servo did in lab 4. You can achieve a smooth motion by incrementally increasing and decreasing your pulsewidth.
|
||||
2. The last step is to add a pushbutton interrupt to start the windshield wiper. You can choose either a pin change or an external interrupt as a source.
|
||||
3. Submit a video of your working system (or bring it to me for a demonstration).
|
||||
|
||||
```c
|
||||
unsigned long servoValue=0, prevValue=0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(9,OUTPUT);
|
||||
Serial.begin(9600);
|
||||
TCCR1A=0xB2;
|
||||
TCCR1B=0x1B;
|
||||
ICR1=0x1387;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(10);
|
||||
prevValue = servoValue;
|
||||
while ((servoValue>=525) || (prevValue > servoValue))
|
||||
{
|
||||
if (servoValue > 0){
|
||||
servoValue--;
|
||||
OCR1A=144+servoValue;
|
||||
Serial.println(OCR1A);
|
||||
delay(10);
|
||||
}
|
||||
else{break;}
|
||||
}
|
||||
if (prevValue == servoValue) {servoValue++;}
|
||||
OCR1A=144+servoValue;
|
||||
Serial.println(OCR1A);
|
||||
}
|
||||
```
|
||||
|
||||
[link to video](https://drive.google.com/file/d/1-DiePSXHLN-g091YAH-m3jBtCqhLYHJB/view?usp=drivesdk)
|
||||
|
||||
3. Rewrite Q1 of HW#4, using PWM mode instead of CTC mode.
|
||||
|
||||
Because the code is quite lengthy, code modifications can be seen in lines 35, 36, and 44.
|
||||
|
||||
```c
|
||||
//Note-name/constant conversion
|
||||
#define LA 36363
|
||||
#define LAS 34323
|
||||
#define LB 32396
|
||||
#define LC 30578
|
||||
#define LCS 28861
|
||||
#define LD 27242
|
||||
#define LDS 25713
|
||||
#define LE 24270
|
||||
#define LF 22908
|
||||
#define LFS 21622
|
||||
#define LG 20408
|
||||
#define LGS 19263
|
||||
#define MA 18182
|
||||
#define MAS 17161
|
||||
#define MB 16198
|
||||
#define MC 15289
|
||||
#define MCS 14430
|
||||
#define MD 13620
|
||||
#define MDS 12856
|
||||
#define ME 12135
|
||||
#define MF 11454
|
||||
#define MFS 10811
|
||||
#define MG 10204
|
||||
#define MGS 9631
|
||||
#define HA 9091
|
||||
|
||||
//Note Length definitions
|
||||
#define QUARTER 400
|
||||
#define EIGHTH 200
|
||||
#define DOTQUARTER 600
|
||||
#define HALF 800
|
||||
|
||||
void setup(){
|
||||
TCCR1A=0b10100011;
|
||||
TCCR1B=0b00011001;
|
||||
TCCR1C=0;
|
||||
TCNT1=0;
|
||||
DDRB|=0x02;
|
||||
}
|
||||
|
||||
void playNote(int note, int time){
|
||||
OCR1A = note;
|
||||
OCR1B = note / 2;
|
||||
delay(time);
|
||||
OCR1A = 0;
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MD, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LD, QUARTER);
|
||||
playNote(LD, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MC, QUARTER);
|
||||
playNote(MD, DOTQUARTER);
|
||||
playNote(MD, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(LG, EIGHTH);
|
||||
playNote(LFS, EIGHTH);
|
||||
playNote(LG, HALF);
|
||||
playNote(MD, HALF);
|
||||
playNote(MB, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, DOTQUARTER);
|
||||
playNote(LD, EIGHTH);
|
||||
playNote(LG, HALF);
|
||||
playNote(LG, DOTQUARTER);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MD, QUARTER);
|
||||
playNote(MC, EIGHTH);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MA, QUARTER);
|
||||
playNote(MB, QUARTER);
|
||||
playNote(MB, EIGHTH);
|
||||
playNote(MA, EIGHTH);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, QUARTER);
|
||||
playNote(LG, HALF);
|
||||
delay(1000);
|
||||
}
|
||||
```
|
||||
|
BIN
Homework/hw6.pdf
Normal file
BIN
Homework/hw7.docx
Normal file
168
Homework/hw7.md
Normal file
|
@ -0,0 +1,168 @@
|
|||
1. Control the movement of a servo motor using the gyroscope from lab. Use the library functions for the MPU6050 used in lab. The servo should be controlled with timer 1, starting at 0 degrees (pulsewidth $1.5\mu s$), and have a range of motion of $\pm90^\circ$
|
||||
|
||||
```c++
|
||||
#include <Wire.h>
|
||||
#include <MPU6050.h>
|
||||
#define SERVOrotate 500
|
||||
#define SERVO 375
|
||||
#define degree 5
|
||||
|
||||
|
||||
MPU6050 mpu; // declare a variable called mpu of datatype MPU6050
|
||||
unsigned long timeStampStartOfLoopMs = 0;
|
||||
float timeStepS = 0.01;
|
||||
float yaw = 0.0f; // pitch, roll and yaw values
|
||||
|
||||
unsigned long posistion = 0;
|
||||
|
||||
Vector normalizedGyroDPS; //stores the three gyroscope readings XYZ in degrees per second (DPS)
|
||||
volatile bool newDataFlag=false; // boolean flag to indicate that timer1 overflow has occurred
|
||||
unsigned long startMicroseconds,elapsedMicroseconds; // use for profiling time for certain tasks
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
cli();
|
||||
TCCR1A = 0b00100010; //Mode 14 fast PWM, 256 scalar
|
||||
TCCR1B = 0b00011101;
|
||||
TIMSK1 |= 0b00000100; //enable timer 1 overflow interrupt
|
||||
ICR1 = 4999;
|
||||
OCR1A = SERVO;
|
||||
sei();
|
||||
|
||||
while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
|
||||
|
||||
{
|
||||
Serial.println("Could not find a valid MPU6050 sensor, check wiring.");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
mpu.calibrateGyro();
|
||||
mpu.setThreshold(1);
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void loop()
|
||||
{
|
||||
normalizedGyroDPS = mpu.readNormalizeGyro();
|
||||
|
||||
yaw = yaw + normalizedGyroDPS.ZAxis * timeStepS;
|
||||
Serial.println(yaw);
|
||||
|
||||
posistion = (SERVOrotate - SERVO) * yaw / degree;
|
||||
OCR1A = SERVO + servoValue;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
```
|
||||
|
||||
2. Write the instructions necessary to initialize the microcontroller for I^2^C fast mode to write `0xF0` to the `0xAA` register in the peripheral address `0b1001101`.
|
||||
|
||||
```c++
|
||||
void initI2C (unsigned long bit_rate){
|
||||
TWBR = ((16000000/bit_rate)-16)/2; //TWBR set
|
||||
TWCR |= 0b00000100;
|
||||
DDRC &= 0b11001111;
|
||||
PORTC |= 0b00110000; //initialize pins PC4/PC5 as pullups (clocks idle high)
|
||||
}
|
||||
|
||||
void i2cWaitForComplete(){
|
||||
while(!(TWCR & 0x80)){} //wait until TWINT is true
|
||||
}
|
||||
|
||||
void i2cStart(){
|
||||
TWCR = 0b10100100; //clear interrupt, initiate start, enable TWI
|
||||
i2cWaitForComplete(); //wait to know start is complete
|
||||
}
|
||||
|
||||
void i2cStop(){
|
||||
TWCR = 0b10010100; //clear interrupt, initiate stop, enable TWI
|
||||
}
|
||||
|
||||
void i2cSend(byte data){
|
||||
TWDR = data;
|
||||
TWCR = 0b10000100; //clear interrupt and enable
|
||||
i2cWaitForComplete(); //wait to know data is sent
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(9600);
|
||||
initI2C(400000);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
i2cStart();
|
||||
i2cSend(0b10011010);
|
||||
i2cSend(0xAA);
|
||||
i2cSend(0xF0);
|
||||
i2cStop();
|
||||
}
|
||||
```
|
||||
|
||||
3. Write the instructions necessary to initialize the microcontroller for I^2^C standard mode to read 4 bytes of data from register `0x0F` in a peripheral at address `0b1001101`. Each byte of data read should be stored in a different variable.
|
||||
|
||||
```c++
|
||||
byte read_data0, read_data1, read_data2, read_data3;
|
||||
void initI2C (unsigned long bit_rate){
|
||||
TWBR = ((16000000/bit_rate)-16)/2; //TWBR set
|
||||
TWCR |= 0b00000100;
|
||||
DDRC &= 0b11001111;
|
||||
PORTC |= 0b00110000; //initialize pins PC4/PC5 as pullups (clocks idle high)
|
||||
}
|
||||
|
||||
void i2cWaitForComplete(){
|
||||
while(!(TWCR & 0x80)){} //wait until TWINT is true
|
||||
}
|
||||
|
||||
void i2cStart(){
|
||||
TWCR = 0b10100100; //clear interrupt, initiate start, enable TWI
|
||||
i2cWaitForComplete(); //wait to know start is complete
|
||||
}
|
||||
|
||||
void i2cStop(){
|
||||
TWCR = 0b10010100; //clear interrupt, initiate stop, enable TWI
|
||||
}
|
||||
|
||||
void i2cSend(byte data){
|
||||
TWDR = data;
|
||||
TWCR = 0b10000100; //clear interrupt and enable
|
||||
i2cWaitForComplete(); //wait to know data is sent
|
||||
}
|
||||
|
||||
byte i2cReadAck(){ //multi-read
|
||||
TWCR = 0b11000100; //clear interrupt, allow ACK, enable TWI
|
||||
i2cWaitForComplete(); //wait to know data is recieved
|
||||
return(TWDR); //return recieved data
|
||||
}
|
||||
|
||||
byte i2cReadNoAck(){ //single read (always done eventually)
|
||||
TWCR = 0b10000100; //clear interrupt, enable TWI
|
||||
i2cWaitForComplete(); //wait to know data is recieved
|
||||
return(TWDR); //return recieved data
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(9600);
|
||||
initI2C(100000);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
i2cStart();
|
||||
i2cSend(0b10011010);
|
||||
i2cSend(0x0F);
|
||||
i2cStart();
|
||||
i2cSend(0b10011011);
|
||||
read_data0 = i2cReadAck();
|
||||
read_data1 = i2cReadAck();
|
||||
read_data2 = i2cReadAck();
|
||||
read_data3 = i2cReadNoAck();
|
||||
i2cStop();
|
||||
}
|
||||
```
|
BIN
Homework/hw9.docx
Normal file
82
Homework/hw9.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
1. Write a program to quantize the analog input from a $10k\Omega$ potentiometer fed to channel ADC02, and create a light dimmer that dims and brightens an LED using a PWM signal. Consider the following setup:
|
||||
|
||||
1. A $10k\Omega$ potentiometer is connected to analog input channel 2 (`ADC02`)
|
||||
2. The potentiometer is connected to +5V and GND, via suitable resistors.
|
||||
3. Utilize the on-board LED (on the Arduino) to create a dimmer routine.
|
||||
|
||||
The potentiometer should be connecteed to an analog input pin. It will put a voltage between 0 and 5 volts on the input pin. This voltage will be converted in the ADC to a digital number between 0 and 1023 acording to the following formula:
|
||||
$$
|
||||
ADC_{digital}={V_{in}*1023\over V_{ref}}
|
||||
$$
|
||||
A lights brightness is can be controlled by a PWM signal. The higher the duty cycle, the brighter the light. The mappings of input voltage, ADC and duty cycle is shown below:
|
||||
|
||||
| Duty Cycle | 0% | 25% | 50% | 75% | 100% |
|
||||
| ---------- | ---- | ----- | ---- | ----- | ---- |
|
||||
| $V_{in}$ | 0V | 1.25V | 2.5V | 3.75V | 5V |
|
||||
| ADC | 0 | 255 | 511 | 767 | 1023 |
|
||||
|
||||
Since the mapping is linear, you can set up the equation of a line and determine the pulsewidth for the PWM signal for any ADC value between 0-1023.
|
||||
|
||||
Your program should use the free-running mode of the ADC to continuously sample to analog input from the potentiometer. The ADC value should be put into a formula to set the appropriate register to regulate the pulsewidth of the PWM signal.
|
||||
|
||||
```c
|
||||
void setup()
|
||||
{
|
||||
DDRC |= 0x04;
|
||||
ADMUX = 0x43;
|
||||
ADCSRA = 0xAD;
|
||||
ADCSRA |= 0x40;
|
||||
TCCR1A = 0x02;
|
||||
TCCR1B = 0x1B;
|
||||
ICR1 = 62535;
|
||||
OCR1A = 0;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(1){}
|
||||
}
|
||||
ISR(ADC_vect)
|
||||
{
|
||||
byte tempVar = ADCL;
|
||||
int pwmChange = 64 * tempVar;
|
||||
OCR1A = pwmChange;
|
||||
}
|
||||
```
|
||||
|
||||
2. A potentiometer can also be used to turn the arm of a servo motor. As the potentiometer goes from 0-5V, the servo motor follows from $-90^\circ\leftrightarrow90^\circ$. In thatt a servo's angle is controlled by the pulsewidth of the PWM signal, a linear mapping of pulsewidth to ADC value can be defined. The mapping of angle to voltage to ADC value is shown below.
|
||||
|
||||
| angle ($^\circ$) | -90 | -45 | 0 | 45 | 90 |
|
||||
| ---------------- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Pulsewidth (ms) | 1 | 1.25 | 1.5 | 1.75 | 2 |
|
||||
| $V_{in}$ (V) | 0 | 1.25 | 2.5 | 3.75 | 5 |
|
||||
| ADC | 0 | 255 | 511 | 767 | 1023 |
|
||||
|
||||
Repeat the exercise from problem 1, but this time controlling the servo. Remember that you must come up with an equation of the line so that you can set the pulsewidth for any input voltage on a continuous range.
|
||||
|
||||
```c
|
||||
void setup()
|
||||
{
|
||||
DDRC |= 0x04;
|
||||
ADMUX = 0x43;
|
||||
ADCSRA = 0xAD;
|
||||
ADCSRA |= 0x40;
|
||||
TCCR1A = 0x02;
|
||||
TCCR1B = 0x1B;
|
||||
ICR1 = 62499;
|
||||
OCR1A = 93;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(1){}
|
||||
}
|
||||
ISR(ADC_vect)
|
||||
{
|
||||
byte tempVar = ADCL;
|
||||
int pwmChange = ((62 / 1023) * tempVar) + 62;
|
||||
OCR1A = pwmChange;
|
||||
}
|
||||
```
|
||||
|
||||
|
BIN
Homework/hw9.pdf
Normal file
59
Homework/servo_mpu6050/servo_mpu6050.ino
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <Wire.h>
|
||||
#include <MPU6050.h>
|
||||
#define SERVOrotate 500
|
||||
#define SERVO 375
|
||||
#define degree 5
|
||||
|
||||
|
||||
MPU6050 mpu; // declare a variable called mpu of datatype MPU6050
|
||||
unsigned long timeStampStartOfLoopMs = 0;
|
||||
float timeStepS = 0.01;
|
||||
float yaw = 0.0f; // pitch, roll and yaw values
|
||||
|
||||
unsigned long posistion = 0;
|
||||
|
||||
Vector normalizedGyroDPS; //stores the three gyroscope readings XYZ in degrees per second (DPS)
|
||||
volatile bool newDataFlag=false; // boolean flag to indicate that timer1 overflow has occurred
|
||||
unsigned long startMicroseconds,elapsedMicroseconds; // use for profiling time for certain tasks
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
cli();
|
||||
TCCR1A = 0b00100010; //Mode 14 fast PWM, 256 scalar
|
||||
TCCR1B = 0b00011101;
|
||||
TIMSK1 |= 0b00000100; //enable timer 1 overflow interrupt
|
||||
ICR1 = 4999;
|
||||
OCR1A = SERVO;
|
||||
sei();
|
||||
|
||||
while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
|
||||
|
||||
{
|
||||
Serial.println("Could not find a valid MPU6050 sensor, check wiring.");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
mpu.calibrateGyro();
|
||||
mpu.setThreshold(1);
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void loop()
|
||||
{
|
||||
normalizedGyroDPS = mpu.readNormalizeGyro();
|
||||
|
||||
yaw = yaw + normalizedGyroDPS.ZAxis * timeStepS;
|
||||
Serial.println(yaw);
|
||||
|
||||
posistion = (SERVOrotate - SERVO) * yaw / degree;
|
||||
OCR1A = SERVO + servoValue;
|
||||
}
|
||||
|
||||
//==============================================================================
|
59
Homework/sketch_mar24a/sketch_mar24a.ino
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <Wire.h>
|
||||
#include <MPU6050.h>
|
||||
#define SERVOrotate 500
|
||||
#define SERVO 375
|
||||
#define degree 5
|
||||
|
||||
|
||||
MPU6050 mpu; // declare a variable called mpu of datatype MPU6050
|
||||
unsigned long timeStampStartOfLoopMs = 0;
|
||||
float timeStepS = 0.01;
|
||||
float yaw = 0.0f; // pitch, roll and yaw values
|
||||
|
||||
unsigned long posistion = 0;
|
||||
|
||||
Vector normalizedGyroDPS; //stores the three gyroscope readings XYZ in degrees per second (DPS)
|
||||
volatile bool newDataFlag=false; // boolean flag to indicate that timer1 overflow has occurred
|
||||
unsigned long startMicroseconds,elapsedMicroseconds; // use for profiling time for certain tasks
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
cli();
|
||||
TCCR1A = 0b00100010; //Mode 14 fast PWM, 256 scalar
|
||||
TCCR1B = 0b00011101;
|
||||
TIMSK1 |= 0b00000100; //enable timer 1 overflow interrupt
|
||||
ICR1 = 4999;
|
||||
OCR1A = SERVO;
|
||||
sei();
|
||||
|
||||
while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
|
||||
|
||||
{
|
||||
Serial.println("Could not find a valid MPU6050 sensor, check wiring.");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
mpu.calibrateGyro();
|
||||
mpu.setThreshold(1);
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void loop()
|
||||
{
|
||||
normalizedGyroDPS = mpu.readNormalizeGyro();
|
||||
|
||||
yaw = yaw + normalizedGyroDPS.ZAxis * timeStepS;
|
||||
Serial.println(yaw);
|
||||
|
||||
posistion = (SERVOrotate - SERVO) * yaw / degree;
|
||||
OCR1A = SERVO + servoValue;
|
||||
}
|
||||
|
||||
//==============================================================================
|
22
Homework/teamContract.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Team Contract
|
||||
|
||||
As a group, we will
|
||||
|
||||
1. Agree to do an equal share of the work, ensuring an understanding of the problems, and communicating when discrepancies arise
|
||||
2. Notify other team members when they are unavailable, or when questions are incomplete
|
||||
3. Be open to differing approaches, and listen to new ideas
|
||||
|
||||
Meetings will be on Tuesdays from 4-5pm in Gleason 1360, although if necessary it may run longer, as the lab is open until the end of the day. If possible, each individual will have their part of the homework done. The meeting will be to finish homework, if necessary, and discuss issues that we had with said problems. Homework will be turned in by the end of the meeting.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
BIN
atmegaPinout.png
Executable file
After Width: | Height: | Size: 247 KiB |
8
classDescription.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
CPET-251-03
|
||||
Microcontroller Systems
|
||||
Professor: Holly Dickens
|
||||
Semester: 2195 (2020 Spring)
|
||||
Time Slot: MWF 10-11 (10-11am)
|
||||
|
||||
Professor Dickens was a wonderful professor. She is very well versed in the topics of the class, and is willing to teach something multiple times if certain students don't understand a topic. She is very passionate about the subject as well, and is happy to give more information than necessary if students are interested in a particular topic.
|
||||
Being very math/programming inclined, and because the course has prerequisites of similarly based courses, we found that we did very well in this class, with not too much additional effort. Time estimate for work amount unavailable, as this document is being created after taking the class, and an estimate is impossible to make. Tests were fairly straightforward, assuming you understood the material. REFERENCE DIAGRAMS HANDED OUT IN CLASS ARE ESSENTIAL FOR SUCCESS. DO NOT LOSE THEM.
|