Close

Code time!

A project log for Shakelet - alerts for the hard of hearing

A wireless vibrating wristband to notify hard of hearing people of telephones, doorbells and other sound alerts.

alex-huntAlex Hunt 06/12/2016 at 15:080 Comments

I have finally got round to putting my draft code online (GitHub). This is probably the weakest part of the project at the moment. In this post I will concentrate on the issues with the sensor code. Here is the full main.c:

// ------- Preamble -------- //
#include <avr/io.h>                  	// Defines pins, ports, etc
#include <util/delay.h>            		// Functions to waste time
#include <stdlib.h>
#include "pinDefines.h"
#include "piezo.h"
#include "nrf24l01.h"
#include <avr/interrupt.h>

volatile uint16_t adcValue = 0;
volatile uint16_t middleValue = 511;
volatile uint16_t highValue = 520;
volatile uint16_t lowValue = 500;
volatile uint16_t noiseVolume = 0;
volatile uint8_t padding = 20;
volatile uint8_t ADCCount = 0;

void sendSignal(void){
	initNRF24L01();
	
	//Reset MOSI pin (PB0) to allow signal to be sent again
	RF_DDR &= ~(1<<RF_MOSI);
	RF_PORT|= (1<<RF_MOSI);
	
	reset();
	uint8_t W_buffer;
	W_buffer=0x01;
	
	int retries; //Send signal multiple times
	for (retries=0;retries<5;retries++){
		transmit_payload(W_buffer);
	}
}


ISR(ADC_vect){
	//Shift result left by 8 bits as using left align - allows full 10 bits to be captured
	adcValue = ADCH;
		
	// moving average -- tracks sensor's bias voltage
	middleValue = adcValue + middleValue - ((middleValue - 8) >> 4);
	
	// moving averages for positive and negative parts of signal
	if (adcValue > (middleValue >> 4)) {
		highValue = adcValue + highValue - ((highValue - 8) >> 4);
	}
	if (adcValue < (middleValue >> 4)) {
		lowValue = adcValue + lowValue - ((lowValue - 8) >> 4);
	}
	
	// "padding" provides a minimum value for the noise volume
	noiseVolume = highValue - lowValue + padding;
	
		// Now check to see if ADC value above or below thresholds 
		// Comparison with >> 4 b/c EWMA is on different scale 
		if (adcValue < ((middleValue - noiseVolume) >> 4)) {
			sendSignal();
		}
		else if (adcValue > ((middleValue + noiseVolume) >> 4)) {
			
			sendSignal();
		
	}
}


int main(void) 
{
	
	initSPI();
	initADC();
	initNRF24L01();
	
  while(1)
  {
	if (adcValue>2000){
		sendSignal();
	}
	
  }

  return 0;
}

ADC ISR is intended to use an exponentially weighted moving average for assessing when the ADC value is significantly high enough. The key parts were taken from the excellent book Make: AVR Programming by Elliott Williams (available on amazon.co.uk) which was my gateway drug into this hobby and which I really can't recommend highly enough.

The ADC is running in free-running mode. However, as I haven't yet looked at how to put the attiny into sleep mode whilst keeping the ADC running, I have fudged the main loop at the moment by just including a conditional statement that can never be met. This is something I hope to correct over the next week as it is clearly not an efficient way to program.

The other thing you will notice is that the data sent is just a random buffer. Eventually I will send a separate identification code for each sensor so that the bracelet will be able to determine which one has been triggered. However, for reasons I can't quite work out the data received by the bracelet is not the same as that being sent so this is again an issue that needs looking at.

The bracelet is another hornet's nest of patchy coding and I will turn my attention to this once I am happy with the sensor side. The list of things to do seems to be getting longer!

Discussions