Saturday, August 27, 2016

Combining Arduino, Android, and the Cloud Part 2

In this 3 part series we look at how to create an Android app to monitor and control multiple WiFi enabled Arduinos using the cloud. In part 2 we will look at how to grab the Arduino data from the cloud using a custom Android App.




To download the Android App .aia file to load into MIT App Inventor II use the following link: https://dl.dropboxusercontent.com/u/26591541/CloudHomeAutoEx.aia

Wednesday, August 24, 2016

Combining Arduino, Android, and the Cloud Part 1

In this 3 part series we look at how to create an Android app to monitor and control multiple WiFi enabled Arduinos using the cloud. In part 1 we will look at how to send data to the cloud from an Arduino MKR1000 and an Arduino ESP8266.



//**********************Arduino ESP8266 Code****************
/*
 This sketch was created for a tutorial called Combining Arduino, Android, and the Cloud Part 1 
 That was presented on the ForceTronics YouTube Channel. This code is public domain for anybody to 
 use or modify at your own risk

 Note that this code was leveraged from a Sparkfun example 
 on using their cloud service Phant
 */

// Include the ESP8266 WiFi library. (Works a lot like the
// Arduino WiFi library.)
#include <ESP8266WiFi.h>
// Include the SparkFun Phant library.
#include <Phant.h>

//Set your network name and password
const char WiFiSSID[] = "Yournetwork";
const char WiFiPSK[] = "Yourpassword";

//define constants for pin control and node number
const int LED_PIN = 5; // Thing's onboard, green LED
const int ANALOG_PIN = A0; // The only analog pin on the Thing
const int NODE_NUM = 1; //node identifier

//declare phant address and security keys
const char PhantHost[] = "data.sparkfun.com";
const char PublicKey[] = "yourpublickey";
const char PrivateKey[] = "yourprivatekey";

//specify the rate that you post data to cloud
const unsigned long postRate = 15000;
unsigned long lastPost = 0;

void setup() 
{
  initHardware(); //setup arduino hardware
  connectWiFi(); //Connect your WiFi network
  digitalWrite(LED_PIN, HIGH);
}

void loop() 
{ //loop until it is time to post data to phant cloud
  if (lastPost + postRate <= millis())
  {
    if (postToPhant())
      lastPost = millis();
    else
      delay(100);    
  }
}

//function used to connect to WiFi network
void connectWiFi()
{
  byte ledStatus = LOW;
  // Set WiFi mode to station (as opposed to AP or AP_STA)
  WiFi.mode(WIFI_STA);
  // WiFI.begin([ssid], [passkey]) initiates a WiFI connection
  // to the stated [ssid], using the [passkey] as a WPA, WPA2,
  // or WEP passphrase.
  WiFi.begin(WiFiSSID, WiFiPSK);
  
  // Use the WiFi.status() function to check if the ESP8266
  // is connected to a WiFi network.
  while (WiFi.status() != WL_CONNECTED)
  {
    // Blink the LED
    digitalWrite(LED_PIN, ledStatus); // Write LED high/low
    ledStatus = (ledStatus == HIGH) ? LOW : HIGH;
    
    // Delays allow the ESP8266 to perform critical tasks
    // defined outside of the sketch. These tasks include
    // setting up, and maintaining, a WiFi connection.
    delay(100);
    // Potentially infinite loops are generally dangerous.
    // Add delays -- allowing the processor to perform other
    // tasks -- wherever possible.
  }
}

//function that sets up some initial hardware states
void initHardware()
{
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
}

//this function takes data and posts it to the cloud
int postToPhant()
{
  // LED turns on when we enter, it'll go off when we 
  // successfully post.
  digitalWrite(LED_PIN, HIGH);
  
  // Declare an object from the Phant library - phant
  Phant phant(PhantHost, PublicKey, PrivateKey);
  //These functions build data and field string that will be sent to phant cloud
  phant.add("adcdata", analogRead(ANALOG_PIN));
  phant.add("wifinode", NODE_NUM);
  
  // Now connect to data.sparkfun.com, and post our data:
  WiFiClient client; //declare client object that will post the data
  const int httpPort = 80; //specify port to post through
  
  if (!client.connect(PhantHost, httpPort)) //attempt to connect to phant
  {
    // If we fail to connect, return 0.
    return 0;
  }
 //Send post to phant
  client.print(phant.post());
  
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    //Serial.print(line); // Trying to avoid using serial
  }
  
  // Before we exit, turn the LED off.
  digitalWrite(LED_PIN, LOW);
  
  return 1; // Return success
}

//**********************Arduino MKR1000 Code****************
  /*
 This sketch was created for a tutorial called Combining Arduino, Android, and the Cloud Part 1 
 That was presented on the ForceTronics YouTube Channel. This code is public domain for anybody to 
 use or modify at your own risk

 Note that this code was leveraged from the Arduino WiFi101 examples and from a Sparkfun example 
 on using their cloud service Phant
 */


#include <SPI.h>
#include <WiFi101.h>

char ssid[] = "YourNetwork"; //  your network SSID (name)
char pass[] = "YourPassword";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

//define some constant variables for pins and node number
const int LED_PIN = 6; // Thing's onboard, green LED
const int ANALOG_PIN = A0; // The only analog pin on the Thing
const int NODE_NUM = 2; //node identifier

//define areas for phant cloud address and security keys
const char PhantHost[] = "data.sparkfun.com";
const char PublicKey[] = "YourKey";
const char PrivateKey[] = "YourKey";
String _pub;
String _prv;
String _host;
String _params;
static const char HEADER_POST_URL1[] PROGMEM = "POST /input/";
static const char HEADER_POST_URL2[] PROGMEM = ".txt HTTP/1.1\n";
static const char HEADER_PHANT_PRV_KEY[] PROGMEM = "Phant-Private-Key: ";
static const char HEADER_CONNECTION_CLOSE[] PROGMEM = "Connection: close\n";
static const char HEADER_CONTENT_TYPE[] PROGMEM = "Content-Type: application/x-www-form-urlencoded\n";
static const char HEADER_CONTENT_LENGTH[] PROGMEM = "Content-Length: ";

//timing for posting to the phant cloud
const unsigned long postRate = 15000;
unsigned long lastPost = 0;

void setup() {
  pinMode(LED_PIN, OUTPUT); //setup LED pin
  digitalWrite(LED_PIN, LOW);
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();
}

void loop() {
  if (lastPost + postRate <= millis())
  {
    if (postToPhant())
      lastPost = millis();
    else
      lastPost = millis(); //Even if we fail delay whole cycle before we try again    
  }
}

int postToPhant()
{
  // LED turns on when we enter, it'll go off when we successfully post.
  digitalWrite(LED_PIN, HIGH);
  
  // Declare an object from the Phant library - phant
  phant(PhantHost, PublicKey, PrivateKey);
  //These calls build the web communication strings with Phant
  phantAdd("adcdata", analogRead(ANALOG_PIN)); //specify field and data used in that field
  phantAdd("wifinode", NODE_NUM);
  
  WiFiClient client; //Create client object to communicate with the phant server

  if (!client.connect(PhantHost, 80)) { //Attempt to connect to phant server using port 80
    // If we fail to connect, return 0.
    return 0;
  }

  //Send post to phant server
  client.print(phantPost()); 
  
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    String line = client.readStringUntil('\r');
    //Do something with data
  }
  client.stop();
 // Before we exit, turn the LED off.
  digitalWrite(LED_PIN, LOW);
  
  return 1; // Return success
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  Serial.println();
}


//This is from phant library, initializes variables
void phant(String host, String publicKey, String privateKey) {
  _host = host;
  _pub = publicKey;
  _prv = privateKey;
  _params = "";
}

//From phant library, builds string of field and data
void phantAdd(String field, int data) {

  _params += "&" + field + "=" + String(data);

}

//From phant library, builds the string used to post data to phant over web services
String phantPost() {

  String params = _params.substring(1);
  String result;
  //String result = "POST /input/" + _pub + ".txt HTTP/1.1\n";
  for (int i=0; i<strlen(HEADER_POST_URL1); i++)
  {
    result += (char)pgm_read_byte_near(HEADER_POST_URL1 + i);
  }
  result += _pub;
  for (int i=0; i<strlen(HEADER_POST_URL2); i++)
  {
    result += (char)pgm_read_byte_near(HEADER_POST_URL2 + i);
  }
  result += "Host: " + _host + "\n";
  //result += "Phant-Private-Key: " + _prv + "\n";
  for (int i=0; i<strlen(HEADER_PHANT_PRV_KEY); i++)
  {
    result += (char)pgm_read_byte_near(HEADER_PHANT_PRV_KEY + i);
  }
  result += _prv + '\n';
  //result += "Connection: close\n";
  for (int i=0; i<strlen(HEADER_CONNECTION_CLOSE); i++)
  {
    result += (char)pgm_read_byte_near(HEADER_CONNECTION_CLOSE + i);
  }
  //result += "Content-Type: application/x-www-form-urlencoded\n";
  for (int i=0; i<strlen(HEADER_CONTENT_TYPE); i++)
  {
    result += (char)pgm_read_byte_near(HEADER_CONTENT_TYPE + i);
  }  
  //result += "Content-Length: " + String(params.length()) + "\n\n";
  for (int i=0; i<strlen(HEADER_CONTENT_LENGTH); i++)
  {
    result += (char)pgm_read_byte_near(HEADER_CONTENT_LENGTH + i);
  } 
  result += String(params.length()) + "\n\n";
  result += params;

  _params = "";
  return result;
}

Monday, August 15, 2016

How to Build an Android App to Control Your WiFi Enabled Arduino


In this video we look at how to make a simple Android App to control your Arduino via WiFi



To download the Andriod App .aia file to load into MIT App Inventor: https://dl.dropboxusercontent.com/u/26591541/HomeAutoEx.aia


Arduino Code from video:
//This sketch made for a video tutorial on the ForceTronics YouTube Channel
//The tutorial shows how to make a simple Android app to control an Arduino wirelessly via WiFi
//This sketch leverages code from the Arduino example programs "AP_SimpleWebServer" and "WiFiWebServer"
//This sketch is free and open to be used and modified

#include <SPI.h> //What is used to communicate witht he WiFi chip
#include <WiFi101.h> //Wifi library fro Arduino MKR1000 and WiFi shield

int lControl =  6; //Digital pin that LED is connected to on the MKR1000
char ssid[] = "YourNetwork";      // your network SSID (name)
char pass[] = "YourPassword";   // your network password
int keyIndex = 0;                 // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS; //status of wifi

WiFiServer server(80); //declare server object and spedify port, 80 is port used for internet

void setup() {
  //Uncomment serial for debugging and to see details of WiFi connection
 // Serial.begin(9600);
 // while (!Serial) {
     // wait for serial port to connect. Needed for native USB port only
//  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
  //  Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
 //   Serial.print("Attempting to connect to SSID: ");
 //   Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  server.begin();
  // you're connected now, so print out the status:
 // printWifiStatus();
}


void loop() {
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
   // Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
       // Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();
            client.print("Value at A0 is ");
            client.print(analogRead(A0));
            client.print("<br>");
            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          }
          else {      // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        }
        else if (c != '\r') {    // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(lControl, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(lControl, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
   // Serial.println("client disconnected");
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Sunday, August 7, 2016

Programming Arduino Zero, MKR1000, or any SAMD21 Arduino via Registers

In this video we look at how to program registers on Arduino's based on the SAMD21 MCU, like the Zero and MKR1000. To do this we will leverage the Atmel ASF data structures. This is a great way to access capabilities in the SAMD21 that are not covered by Arduino libraries. The link to the ASF documentation is http://asf.atmel.com/docs/3.16.0/samd21/html/annotated.html


Arduino code from video:
bool tog = false; //variable to toggle digital output
int cDiv = 1; //varible to hold clock divider
int count = 0; //variable to track when to switch clock freq

void setup() {
  PM->CPUSEL.reg = PM_CPUSEL_CPUDIV(1); //Sets CPU frequency: power management struct, CPUSEL union, register variable
  pinMode(3, OUTPUT); //set D3 to output
}

void loop() {
  if(tog) tog = false; //if tog is true turn it false
  else tog =true;
  digitalWrite(3,tog); //set digital output
  count++;  
  if(count > 6) { //check if it is time to change clock frequency
    if(cDiv == 1) cDiv = 4;
    else cDiv = 1;
    PM->CPUSEL.reg = PM_CPUSEL_CPUDIV(cDiv); //PM_CPUSEL_CPUDIV_DIV4_Val
    count = 0;
  }
}

Sunday, July 24, 2016

Using the nRF24L01’s IRQ Pin to Generate an Interrupt with Arduino

In this video we look at how to use the pulse signal from an nRF24L01+ transceiver module's IRQ pin to trigger an interrupt on your Arduino.


Arduino code from video, receiver code first and then transmitter code:
#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+
#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <avr/sleep.h> //library needed to use AVR based sleep API

const int pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)
const int pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command or message to send out
byte gotByte = 0; //used to store payload from transmit module
volatile int count = 0; //tracks the number of interrupts from IRQ
int pCount = 0; //tracks what last count value was so know when count has been updated
RF24 wirelessSPI(pinCE, pinCSN); // Declare object from nRF24 library (Create your wireless SPI) 
const uint64_t pAddress = 0xB00B1E5000LL;  //Create a pipe addresses for the 2 nodes to communicate over, the "LL" is for LongLong type

void setup()   {
  wirelessSPI.begin();  //Start the nRF24 module
  wirelessSPI.setAutoAck(1);                    // Ensure autoACK is enabled so rec sends ack packet to let you know it got the transmit packet payload
  wirelessSPI.enableAckPayload();         //allows you to include payload on ack packet
  wirelessSPI.maskIRQ(1,1,0);               //mask all IRQ triggers except for receive (1 is mask, 0 is no mask)
  wirelessSPI.setPALevel(RF24_PA_LOW); //Set power level to low, won't work well at higher levels (interfer with receiver)
  wirelessSPI.openReadingPipe(1,pAddress);      //open pipe o for recieving meassages with pipe address
  wirelessSPI.startListening();                 // Start listening for messages
  attachInterrupt(1, interruptFunction, FALLING);  //Create interrupt: 0 for pin 2 or 1 for pin 3, the name of the interrupt function or ISR, and condition to trigger interrupt
}

void loop() {

   if(pCount < count) { //If this is true it means count was interated and another interrupt occurred
       Serial.begin(57600);  //start serial to communicate process
       Serial.print("Receive packet number ");
       Serial.println(count); 
       Serial.end(); //have to end serial since it uses interrupts
       pCount = count; 
   }
}

//This is the function called when the interrupt occurs (pin 2 goes high)
//this is often referred to as the interrupt service routine or ISR
//This cannot take any input arguments or return anything
void interruptFunction() {
 count++; //up the receive counter
 while(wirelessSPI.available()) { //get data sent from transmit
       wirelessSPI.read( &gotByte, 1 ); //read one byte of data and store it in gotByte variable
 }

}

//********************Transmitter code**************************** #include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+
#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/
#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/

const int pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)
const int pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command or message to send out
byte counter = 1; //used to count the packets sent
RF24 wirelessSPI(pinCE, pinCSN); // Create your nRF24 object or wireless SPI connection
const uint64_t pAddress = 0xB00B1E5000LL;              // Radio pipe addresses for the 2 nodes to communicate.

void setup()  
{
  Serial.begin(57600);   //start serial to communicate process
  wirelessSPI.begin();            //Start the nRF24 module
  wirelessSPI.setAutoAck(1);                    // Ensure autoACK is enabled so rec sends ack packet to let you know it got the transmit packet payload
  wirelessSPI.enableAckPayload();               // Allow optional ack payloads
  wirelessSPI.setPALevel(RF24_PA_LOW);
  wirelessSPI.openWritingPipe(pAddress);        // pipe address that we will communicate over, must be the same for each nRF24 module
  wirelessSPI.stopListening();        //transmitter so stop listening for data
  randomSeed(analogRead(0));    //use random ADC value to seed random number algorithm
}

void loop() {
  delay(random(100,5000)); //Generate delay time between 100msec and 5 sec
  Serial.println("Sending packet"); 
  if (!wirelessSPI.write( &counter, 1 )){  //if the send fails let the user know over serial monitor
       Serial.println("packet delivery failed");  
  }
   Serial.println();   
}

Saturday, July 2, 2016

Advanced PWM for Arduino Zero or any Atmel SAMD21 Based Arduino Board


The Arduino PWM library leaves a lot to be desired since it really only scratches the surface on PWM capabilities built into today's MCUs. In this video we look at how to unlock some of the more advanced PWM features on any Arduino board based on the Atmel SAMD21 32 bit ARM MCU.



Click here to access the Atmel programming API from the video

Arduino code from video***********************************************************
//This was used for ForceTronics YouTube tutorial on generating PWM signals with SAMD21 based Arduinos
//This code is public domain and can be used by anyone at their own risk
//Some of this code was leveraged from MartinL on Arduino Forum http://forum.arduino.cc/index.php?topic=346731.5;wap2

//sets the period of the PWM signal, PWM period = wPer / gen clock rate 
volatile unsigned char wPer = 255;
//This variable is to generate the duty cycle of the PWM signal 0.5 --> 50%
volatile float pWMDC = .5;
//selects the gen clock for setting the waveform generator clock or sample rate
const unsigned char gClock = 4;
//sets the divide factor for the gen clk, 48MHz / 3 = 16MHz
const unsigned char dFactor = 3;

void setup() 

  pinMode(3, OUTPUT);
  analogReadResolution(8); //set the ADC resolution to match the PWM max resolution (0 to 255)
  
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(dFactor) |          // Divide the main clock down by some factor to get generic clock
                    GCLK_GENDIV_ID(gClock);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           
                     GCLK_GENCTRL_GENEN |         // Enable GCLK4
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                     GCLK_GENCTRL_ID(gClock);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Enable the port multiplexer for the digital pin. Note commented out line is pin D7, other is D3
 // PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;
  PORT->Group[g_APinDescription[3].ulPort].PINCFG[g_APinDescription[3].ulPin].bit.PMUXEN = 1;
  
   //Connect the TCC0 timer to digital output - port pins are paired odd PMUO and even PMUXE (note D7 is commented out and D3 is not)
  // PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F; 
  PORT->Group[g_APinDescription[4].ulPort].PMUX[g_APinDescription[4].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;

  // Feed GCLK4 to TCC0 and TCC1
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  //Set for Single slope PWM operation: timers or counters count up to TOP value and then repeat
  REG_TCC1_WAVE |= TCC_WAVE_WAVEGEN_NPWM;       // Reverse the output polarity on all TCC0 outputs
                   //TCC_WAVE_POL(0xF)      //this line inverts the output waveform
                   //TCC_WAVE_WAVEGEN_DSBOTH;    // Setup dual slope PWM on TCC0
  while (TCC1->SYNCBUSY.bit.WAVE);               // Wait for synchronization

  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation: 
  REG_TCC1_PER = wPer;         // This sets the rate or frequency of PWM signal. 
  while (TCC1->SYNCBUSY.bit.PER);                // Wait for synchronization
  
  // Set the PWM signal to output 50% duty cycle initially (0.5 x 255)
  REG_TCC1_CC1 = pWMDC*wPer;        
  while (TCC1->SYNCBUSY.bit.CC1);                // Wait for synchronization

  //enable interrupts
  REG_TCC1_INTENSET = TCC_INTENSET_OVF; //Set up interrupt at TOP of each PWM cycle
  enable_interrupts(); //enable in NVIC
  
  // Set prescaler and enable the outputs
  REG_TCC1_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 |    // Divide GCLK4 by 1
                    TCC_CTRLA_ENABLE;             // Enable the TCC0 output
  while (TCC1->SYNCBUSY.bit.ENABLE);              // Wait for synchronization
}

void loop() { 

  //Put main code here
 }

//This function sets the interrupts priority to highest and then enables the PWM interrupt
void enable_interrupts() {
  NVIC_SetPriority(TCC1_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority
  NVIC_EnableIRQ(TCC1_IRQn);
}

//This ISR is called at the end or TOP of each PWM cycle
void TCC1_Handler() {
    REG_TCC1_PER = analogRead(A1); //Get period from A1
    while (TCC1->SYNCBUSY.bit.PER);
    REG_TCC1_CC1 = (analogRead(A0)/255.0)*analogRead(A1); //calculate PWM using A0 reading and A1 current state
    while (TCC1->SYNCBUSY.bit.CC1);
    REG_TCC0_INTFLAG = TC_INTFLAG_OVF; //Need to reset interrupt
}

Monday, June 20, 2016

Building a Wireless Sensor Network with the nRF24L01 Part 6


In part 6 we look at the final hardware design, we switch to the TMRh20 library for the nRF24L01, and we look at a library wrapper that makes getting started with your own wireless sensor network real easy. Go to ForceTronics.com to purchase a wireless flex node and go to Github to access the code and PCB design files.