7 Programming

Table of Contents

For programming this week, I made an LED fade in and out, almost like a revolving lighthouse beacon. Because we can't control the amount of voltage reaching the LED (we only control whether it receives +5V or +0V), the light level is controlled by switching the light on and off faster than humans can perceive. The fraction of the time that the light is on dictates how bright the light looks. This technique is known as pulse-width modulation, and as the TAs point out, a similar trick (on a speaker instead of an LED) can be used to generate synthesized sounds in future weeks…

(This video was compressed from 9.7 Mib to 224 KiB by lowering the resolution and the bitrate.)

ffmpeg -i dxh_make_triangle_wave.mp4 -vf scale=400:-2 -vcodec libx264 -crf 20 -an dxh_make_triangle_wave_compressed.mp4 

1 Programming

int program_triangle_fader(void) {
	int inc = 5;

	uint32_t period_i = 0;
	uint32_t period_size = 2000;
	uint32_t on_level = 0;

	uint32_t i;

	 while (1) {
		for(i=0; i<period_size; i+=1) {
			clear(led_port, (1 << PB2));
			set(led_port, ((i < on_level) << PB2));

		}
		on_level += inc;

		if(on_level > period_size) {
			inc = -inc;
		}
		if(on_level < 0) {
			inc = -inc;
		}

	}
}

I made three other programs along the way.

while (1) {
  dxh_i ++;
  // PROGRAM 1: flicker
  if(dxh_i > dxh_freq) {
    dxh_i -= dxh_freq;
    dxh_led = 1-dxh_led;

  }
  clear(led_port,(1 << PB2));
  //set(led_port, (dxh_led << PB2) ); // current state.

  // PROGRAM 2: dimmer
  // clear(led_port,(1 << PB2));
  // set(led_port, (((dxh_i % 2)==0) << PB2) ); // current state.


  // PROGRAM 3: led is on unless you press button
  /* clear(PORTA, (1 << PA2)); */
  /* clear(PORTB, (1 << PB2)); */
  /* PORTB |= PINA; */

2 Notes on how to program.

  1. My workflow is that you write a program in C. Then, you edit the default makefile (for the hello world program) and change the PROJECT variable to the title of your file, e.g. dxh.ftdi.44. This directs the Makefile to compile code from a C file with that name, creating a hex file with that name, etc. Connect the hello-world board to the programmer, and each of them to the computer. You run make attiny-fuses exactly once in the lifetime of your hello-world board to set the fuses. Then run make program-attiny to program the board. The argument attiny varies depending on which kind of architecture you're programming, e.g. avrisp, attiny, etc.
  2. You can use the script avrdude -p t44 -c avrisp2 -v to test whether the things you think are connected are connected as you expect. The -p flag indicates the type of processor, here an ATTiny44. The -c flag indicates the kind of architecture, e.g. avrisp2 is the little blue box programmer in the lab, or attiny. The script will ask the programmer to echo an autobiographical message telling about itself.
  3. The libraries imported by the hello world C program allow you to turn on and off the pins of your microcontroller (e.g. attiny44) by referring to them by name. The schematic diagram which you designed in, e.g., KiCad or Eagle shows the pins of your microcontroller and what they're connected to. For example, in my board pin PB2 is connected to the LED and pin PA2 is connected to the switch.
  4. The way it works conceptually is that if the led is pin PA2, and register A has 8 pins named A0-A7, you can send the signal 00000100 to turn on the LED.
  5. Note! If you turn on or off the pins, they stay on or off for all time. It is like flipping a light switch to a new position more than pushing the pulse button on a blender.
  6. Registers are named after pins (A0, A1, B0, B1, etc.)
  7. Two registers important for writing. To write to port A, for example, uses two registers: DDRA, PORTA. (Similarly, for port B, there's DDRB, PORTB. For a hypothetical port C, there's DDRC and PORTC, etc.)
  8. DDRA is direction. It tells whether each pin is an input (0) or an output (1), so you know whether to read from it like a switch or write to it like an LED.
  9. PORTA defines the output states of the output pin. You write to it to change the value of the outputs.
  10. On inputs, PORTA tells input pins whether to float (0) or not (1). You probably want it not to float for these applications. You might want it to float if connecting to a capacitative element e.g. touch-capacitance.
  11. PINA is another register that records the actual current state of the pins. You never write to it (that's what PORTA is for, to request that a pin changes value), but you can read from it to see where the pins are at.
  12. The clock speed is astonishingly fast (20 MHz), corresponding to about 20 million instructions (~ literal lines of code) per second. To handle the large numbers involved, it is often necessary to use uint32_t datatypes instead of standard int.

Author: Dylan Holmes

Created: 2018-10-24 Wed 12:36

Validate