Mass ccommit

This commit is contained in:
Blizzard Finnegan 2022-02-15 09:22:53 -05:00
parent b7e56eaa90
commit 088090ce1b
No known key found for this signature in database
GPG key ID: 20C7BC51C80B459E
16 changed files with 1204 additions and 0 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@
**/*.log
**/*.gz
**/*.pdf
**/*exam*

12
homework2Answers.md Normal file
View file

@ -0,0 +1,12 @@
1.
a. 4.8875855mV
b. 1.4174mV
c. ~873
d. ~3465
2. 15kHz
3.
a. No
b. 8-12kHz
c. 16kHz

7
homework3Answers.md Normal file
View file

@ -0,0 +1,7 @@
1. 352
2.
a. 0 10000011 00000000000000000000000
b. 0.0258PPM
3.
a. 1010 1011
b. -42 (1010 1010)

BIN
labs/MsTimer2-1.1.0.zip Normal file

Binary file not shown.

View file

@ -0,0 +1,220 @@
/*
MsTimer2.h - Using timer2 with 1ms resolution
Javier Valencia <javiervalencia80@gmail.com>
https://github.com/PaulStoffregen/MsTimer2
History:
6/Jun/14 - V0.7 added support for Teensy 3.0 & 3.1
29/Dec/11 - V0.6 added support for ATmega32u4, AT90USB646, AT90USB1286 (paul@pjrc.com)
some improvements added by Bill Perry
note: uses timer4 on Atmega32u4
29/May/09 - V0.5 added support for Atmega1280 (thanks to Manuel Negri)
19/Mar/09 - V0.4 added support for ATmega328P (thanks to Jerome Despatis)
11/Jun/08 - V0.3
changes to allow working with different CPU frequencies
added support for ATMega128 (using timer2)
compatible with ATMega48/88/168/8
10/May/08 - V0.2 added some security tests and volatile keywords
9/May/08 - V0.1 released working on ATMEGA168 only
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <MsTimer2.h>
unsigned long MsTimer2::msecs;
void (*MsTimer2::func)();
volatile unsigned long MsTimer2::count;
volatile char MsTimer2::overflowing;
volatile unsigned int MsTimer2::tcnt2;
#if defined(__arm__) && defined(TEENSYDUINO)
static IntervalTimer itimer;
#endif
void MsTimer2::set(unsigned long ms, void (*f)()) {
float prescaler = 0.0;
if (ms == 0)
msecs = 1;
else
msecs = ms;
func = f;
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
TIMSK2 &= ~(1<<TOIE2);
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
ASSR &= ~(1<<AS2);
TIMSK2 &= ~(1<<OCIE2A);
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
TCCR2B |= (1<<CS22);
TCCR2B &= ~((1<<CS21) | (1<<CS20));
prescaler = 64.0;
} else if (F_CPU < 1000000UL) { // prescaler set to 8
TCCR2B |= (1<<CS21);
TCCR2B &= ~((1<<CS22) | (1<<CS20));
prescaler = 8.0;
} else { // F_CPU > 16Mhz, prescaler set to 128
TCCR2B |= ((1<<CS22) | (1<<CS20));
TCCR2B &= ~(1<<CS21);
prescaler = 128.0;
}
#elif defined (__AVR_ATmega8__)
TIMSK &= ~(1<<TOIE2);
TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
TIMSK &= ~(1<<OCIE2);
ASSR &= ~(1<<AS2);
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
TCCR2 |= (1<<CS22);
TCCR2 &= ~((1<<CS21) | (1<<CS20));
prescaler = 64.0;
} else if (F_CPU < 1000000UL) { // prescaler set to 8
TCCR2 |= (1<<CS21);
TCCR2 &= ~((1<<CS22) | (1<<CS20));
prescaler = 8.0;
} else { // F_CPU > 16Mhz, prescaler set to 128
TCCR2 |= ((1<<CS22) && (1<<CS20));
TCCR2 &= ~(1<<CS21);
prescaler = 128.0;
}
#elif defined (__AVR_ATmega128__)
TIMSK &= ~(1<<TOIE2);
TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
TIMSK &= ~(1<<OCIE2);
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
TCCR2 |= ((1<<CS21) | (1<<CS20));
TCCR2 &= ~(1<<CS22);
prescaler = 64.0;
} else if (F_CPU < 1000000UL) { // prescaler set to 8
TCCR2 |= (1<<CS21);
TCCR2 &= ~((1<<CS22) | (1<<CS20));
prescaler = 8.0;
} else { // F_CPU > 16Mhz, prescaler set to 256
TCCR2 |= (1<<CS22);
TCCR2 &= ~((1<<CS21) | (1<<CS20));
prescaler = 256.0;
}
#elif defined (__AVR_ATmega32U4__)
TCCR4B = 0;
TCCR4A = 0;
TCCR4C = 0;
TCCR4D = 0;
TCCR4E = 0;
if (F_CPU >= 16000000L) {
TCCR4B = (1<<CS43) | (1<<PSR4);
prescaler = 128.0;
} else if (F_CPU >= 8000000L) {
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4);
prescaler = 64.0;
} else if (F_CPU >= 4000000L) {
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<PSR4);
prescaler = 32.0;
} else if (F_CPU >= 2000000L) {
TCCR4B = (1<<CS42) | (1<<CS40) | (1<<PSR4);
prescaler = 16.0;
} else if (F_CPU >= 1000000L) {
TCCR4B = (1<<CS42) | (1<<PSR4);
prescaler = 8.0;
} else if (F_CPU >= 500000L) {
TCCR4B = (1<<CS41) | (1<<CS40) | (1<<PSR4);
prescaler = 4.0;
} else {
TCCR4B = (1<<CS41) | (1<<PSR4);
prescaler = 2.0;
}
tcnt2 = (int)((float)F_CPU * 0.001 / prescaler) - 1;
OCR4C = tcnt2;
return;
#elif defined(__arm__) && defined(TEENSYDUINO)
// nothing needed here
#else
#error Unsupported CPU type
#endif
tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler);
}
void MsTimer2::start() {
count = 0;
overflowing = 0;
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);
#elif defined (__AVR_ATmega128__)
TCNT2 = tcnt2;
TIMSK |= (1<<TOIE2);
#elif defined (__AVR_ATmega8__)
TCNT2 = tcnt2;
TIMSK |= (1<<TOIE2);
#elif defined (__AVR_ATmega32U4__)
TIFR4 = (1<<TOV4);
TCNT4 = 0;
TIMSK4 = (1<<TOIE4);
#elif defined(__arm__) && defined(TEENSYDUINO)
itimer.begin(MsTimer2::_overflow, 1000);
#endif
}
void MsTimer2::stop() {
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
TIMSK2 &= ~(1<<TOIE2);
#elif defined (__AVR_ATmega128__)
TIMSK &= ~(1<<TOIE2);
#elif defined (__AVR_ATmega8__)
TIMSK &= ~(1<<TOIE2);
#elif defined (__AVR_ATmega32U4__)
TIMSK4 = 0;
#elif defined(__arm__) && defined(TEENSYDUINO)
itimer.end();
#endif
}
void MsTimer2::_overflow() {
count += 1;
if (count >= msecs && !overflowing) {
overflowing = 1;
count = count - msecs; // subtract ms to catch missed overflows
// set to 0 if you don't want this.
(*func)();
overflowing = 0;
}
}
#if defined (__AVR__)
#if defined (__AVR_ATmega32U4__)
ISR(TIMER4_OVF_vect) {
#else
ISR(TIMER2_OVF_vect) {
#endif
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
TCNT2 = MsTimer2::tcnt2;
#elif defined (__AVR_ATmega128__)
TCNT2 = MsTimer2::tcnt2;
#elif defined (__AVR_ATmega8__)
TCNT2 = MsTimer2::tcnt2;
#elif defined (__AVR_ATmega32U4__)
// not necessary on 32u4's high speed timer4
#endif
MsTimer2::_overflow();
}
#endif // AVR

View file

@ -0,0 +1,25 @@
#ifndef MsTimer2_h
#define MsTimer2_h
#ifdef __AVR__
#include <avr/interrupt.h>
#elif defined(__arm__) && defined(TEENSYDUINO)
#include <Arduino.h>
#else
#error MsTimer2 library only works on AVR architecture
#endif
namespace MsTimer2 {
extern unsigned long msecs;
extern void (*func)();
extern volatile unsigned long count;
extern volatile char overflowing;
extern volatile unsigned int tcnt2;
void set(unsigned long ms, void (*f)());
void start();
void stop();
void _overflow();
}
#endif

View file

@ -0,0 +1,7 @@
#MsTimer2 Library#
Run a function every millisecond.
http://www.pjrc.com/teensy/td_libs_MsTimer2.html
Originally written by Javier Valencia

View file

@ -0,0 +1,4 @@
MsTimer2 KEYWORD1
set KEYWORD2
start KEYWORD2
stop KEYWORD2

View file

@ -0,0 +1,25 @@
{
"name": "MsTimer2",
"keywords": "timer, callback",
"description": "MsTimer2 is a small and very easy to use library to interface Timer2 with humans. It's called MsTimer2 because it \"hardcodes\" a resolution of 1 millisecond on timer2.",
"repository": {
"type": "git",
"url": "https://github.com/PaulStoffregen/MsTimer2.git"
},
"authors": [{
"name": "Javier Valencia",
"email": "javiervalencia80@gmail.com",
"url": "http://www.pjrc.com/teensy/td_libs_MsTimer2.html"
}, {
"name": "Paul Stoffregen",
"url": "https://www.pjrc.com/about/",
"maintainer": true
}],
"frameworks": [
"arduino"
],
"platforms": [
"atmelavr",
"teensy"
]
}

View file

@ -0,0 +1,10 @@
name=MsTimer2
version=1.1
author=Javier Valencia
maintainer=Paul Stoffregen
sentence=Run an interrupt function using Timer2
paragraph=
category=Timing
url=http://playground.arduino.cc/Main/MsTimer2
architectures=*

183
week4/lab/ActivePlot.m Normal file
View file

@ -0,0 +1,183 @@
classdef ActivePlot < handle
% ActivePlot Class to create a plot that can be dynamically written to
% while data is being captured.
%
% Input Arguments
%
% ComPort -- Com port of the serial interface to the Arduino -- 3
% BaudRate -- Baudrate of the Comm port Default 9600
% ReadyString -- The string expected from the Arduino to indicate
% that it is up and running -- Default '%Arduino Ready'
% PortTimeOut -- Time out on the serial port (seconds) -- Default 1
% second
%
%
properties
% Set initial values for the graph scale. Allow y-scale to autoscale
maxX = []; % Autoscale
maxY = []; % Autoscale
graphTitleStr = []';
xLabelStr = [];
yLabelStr = [];
gridOn = true;
lineWidth = [];
lineColor = [];
lineStyle = [];
traceData = [];
hFig = []; % Handle to the figure
hAxis = []; % Handle to the axis
end
methods
function obj = ActivePlot(varargin)
% ActivePlot -- Construct an instance of this class
%
p = inputParser;
defaultMaxX = []; % Autoscale X
defaultMaxY = []; % Autoscale Y
defaultTitle = 'Graph Title';
defaultXlabel = 'Sample Number';
defaultYlabel = 'Value';
defaultGridOn = 'True';
defaultLineWidth = 1;
defaultLineColor = 'b';
defaultLineStyle = '-';
p.addParameter('MaxX', defaultMaxX, @isnumeric);
p.addParameter('MaxY', defaultMaxY, @isnumeric);
p.addParameter('GraphTitle', defaultTitle, @ischar);
p.addParameter('XLabel', defaultXlabel, @ischar);
p.addParameter('YLabel', defaultYlabel, @ischar);
p.addParameter('GridOn', defaultGridOn, @islogical);
p.addParameter('LineWidth', defaultLineWidth, @isnumeric);
p.addParameter('LineStyle', defaultLineStyle, @ischar);
p.addParameter('Color', defaultLineColor, @ischar);
p.parse(varargin{:});
inputArgs = p.Results;
obj.maxX = inputArgs.MaxX;
obj.maxY = inputArgs.MaxY;
obj.graphTitleStr = inputArgs.GraphTitle;
obj.xLabelStr = inputArgs.XLabel;
obj.yLabelStr = inputArgs.YLabel;
obj.gridOn = inputArgs.GridOn;
obj.lineWidth = inputArgs.LineWidth;
obj.lineColor = inputArgs.Color;
obj.lineStyle = inputArgs.LineStyle;
end % ActivePlot Constructor
% CreateFigure method
function CreateFigure(obj)
% Create a new figure. Save the handles for the figure and the axis
obj.hFig = figure;
obj.hAxis = gca;
% Add title and Axes labels
obj.TitleGraph;
obj.LabelXAxis;
obj.LabelYAxis;
if obj.gridOn
grid( obj.hAxis, 'on')
end
end
% TitleGraph method
function TitleGraph(obj)
% Title the graph and label the Axes
title( obj.hAxis, obj.graphTitleStr );
end % TitleGraph
% LabelXAxis method
function LabelXAxis( obj )
xlabel( obj.hAxis, obj.xLabelStr );
end % LabelXAxis
% LabelYAxis
function LabelYAxis( obj )
ylabel( obj.hAxis, obj.yLabelStr );
end % LabelYAxis
% Update the active plot
% method UpdatePlot
function UpdatePlot(obj, plotData)
% UpdatePlot
%
% Update the traces on the plot with the data contained in plotData
% array. Right now,the first column of plotData is the x-axis and
% each column is a trace data
%
% If there are no traces then create them
[~,nColumns] = size(plotData);
if isempty( obj.traceData )
% Create a trace for each column of data beyond the first
% column which is the x-axis
for iColumn = 1:nColumns-1
obj.traceData(iColumn) = line(obj.hAxis, 0,0,'LineWidth',obj.lineWidth,...
'Color',obj.lineColor,...
'LineStyle',obj.lineStyle);
end
end
% Update the trace with new data
nTraces = nColumns - 1;
for iTrace = 1:nTraces
set(obj.traceData(iTrace),'XData', plotData(:,1) );
set(obj.traceData(iTrace),'YData', plotData(:,iTrace + 1) );
end
% Rescale the axes if necessary
% Set the X and Y limits. If the max values are empty then
% let MATLAB autoscale
if ~isempty( obj.maxY )
% If the data goes beyond the original max X and Y settings
% then readjust the plot manually
obj.maxY = max( obj.maxY, max(plotData(:,iTrace + 1)) );
obj.hAxis.YLim = [0, obj.maxY];
end
% Set the Y limits. If the max values are empty then let
% MATLAB autoscale
if ~isempty( obj.maxX )
obj.maxX = max( numSamples, max(plotData(:,1)) );
obj.hAxis.XLim = [0, obj.maxX];
end
% Set the grid
if obj.gridOn
grid( obj.hAxis, 'on')
end
drawnow
end
end
end

206
week4/lab/ArduinoSerial.m Normal file
View file

@ -0,0 +1,206 @@
classdef ArduinoSerial < handle
% ArduinoSerial Class to interface to the Arduino Microprocessor
% through the serial port
%
% Input Arguments
%
% ComPort -- Com port of the serial interface to the Arduino -- 3
% BaudRate -- Baudrate of the Comm port Default 9600
% ReadyString -- The string expected from the Arduino to indicate
% that it is up and running -- Default '%Arduino Ready'
% PortTimeOut -- Time out on the serial port (seconds) -- Default 1
% second
%
%
properties
comPort = [];
baudRate = [];
numReadSamples = [];
readStr = [];
writeStr = [];
readyString = [];
arduinoPort = [];
portTimeOut = [];
end
methods
function obj = ArduinoSerial(varargin)
% ArduinoSerial -- Construct an instance of this class
%
p = inputParser;
% If the device is a PC then the Com Port is numeric. If it is
% a MAC then the COM port is a string
if ispc
defaultComPort = 3;
p.addParameter('ComPort', defaultComPort, @isnumeric);
else
defaultComPort = [];
p.addParameter('ComPort',defaultComPort, @ischar);
end
defaultBaudRate = 9600;
defaultReadyString = '%Arduino Ready';
defaultPortTimeOut = 1; % 1 second port time out
p.addParameter('BaudRate', defaultBaudRate, @isnumeric);
p.addParameter('ReadyString', defaultReadyString, @ischar);
p.addParameter('PortTimeOut', defaultPortTimeOut, @isnumeric);
p.parse(varargin{:});
inputArgs = p.Results;
obj.comPort = inputArgs.ComPort;
obj.baudRate = inputArgs.BaudRate;
obj.readyString = inputArgs.ReadyString;
obj.portTimeOut = inputArgs.PortTimeOut;
end
% method OpenSerial
function returnValue = OpenSerial(obj)
%
%
% Close all existing COM ports
if ~isempty(instrfind)
fclose(instrfind);
end
if ischar( obj.comPort )
obj.arduinoPort = serial(sprintf('%s',obj.comPort),...
'BaudRate',obj.baudRate);
else
obj.arduinoPort = serial(sprintf('com%1d',obj.comPort),...
'BaudRate',obj.baudRate);
end
fopen(obj.arduinoPort);
returnValue = true;
% If the port didn't open correctly returnValue will be -1
end
% method ClosePort
function returnValue = ClosePort(obj)
% CloseSerial
%
% Close the arduino serial port
fclose( obj.arduinoPort );
end % ClosePort
% method WaitForReady
function readyFlag = WaitForReady(obj)
% WaitForReady
%
% Arduino will look for a g character to start. Read the port and see if
% the correct string has been sent.
readyFlag = false;
while ~readyFlag
% Idle while waiting for data in the buffer
while ~obj.arduinoPort.BytesAvailable
end
rxString = obj.ReadArduino;
% Echo the string to the command window anyway, but don't
% capture the data in an array just yet
% Check for an end of line character. If there is not one
% then add it
if ~isempty(rxString)
if strcmp(rxString(end), newline) || strcmp(rxString(end), char(13))
fprintf('%s',rxString);
else
fprintf('%s\n',rxString)
end
end
% Check if it is the correct ready string
if regexp( rxString, obj.readyString )
readyFlag = true;
end
end
end
% method WriteString
function WriteString( obj, strValue )
% WriteString
%
% Sends the string argument over the arduino serial port
fprintf(obj.arduinoPort, '%s\n',strValue);
end % WriteString
% method WriteNumeric
function WriteNumeric( obj, numValue )
% WriteNumeric
%
% WriteNumeric first convers numeric argument to a string then
% calls the WriteString method to send the string to the
% Arduino serial port
% Convert the numeric value to a string then send it as a
% string
numericalString = num2str( numValue );
obj.WriteString( numericalString );
end % Write Numeric
%% method ReadArduino
function readString = ReadArduino(obj)
% ReadArduino
%
% ReadArdino reads a string value from the Arduino serial port
% object
readString = fgetl( obj.arduinoPort );
end
%% method WaitForData
function dataAvailable = WaitForData( obj )
% WaitForData
%
% This method checks whether data is available on the port.
% If data is not available before the timeout period the
% method returns false. If there is data in the buffer then
% the method returns true
% Start the timer
dataAvailable = true;
tic
while ~obj.arduinoPort.BytesAvailable
if toc > obj.portTimeOut
dataAvailable = false;
break
end
end
end
end
end

View file

@ -0,0 +1,329 @@
function outData = CaptureArduinoData(varargin)
%% CaptureArduinoData
%
% Function to interface to the serial port to capture data from the
% Arduino.
%
% Input Arguments
%
% Input arguments are in Name/Value pairs
%
% 'ComPort' -- Serial Comm port to communicate with the Arduino
% Default 3
%
% 'BaudRate' -- Baud rate of the Comm Port Default 9600 bps
%
% 'ReadyString' -- Char array of the string from the Arduino letting MATLAB
% know that it is ready -- Object waits for that ready string
% before sending back the response string to tell the Arduino
% to being execution -- Default '%Arduino Ready'
%
% 'PortTimeOut' -- Value in seconds that MATLAB will wait for the serial
% port for a character before timing out -- Default 1 sec
%
%
% 'EchoData' -- Logical value telling MATLAB to echo each string sent from
% the Arduino to the command window -- Default -- true
%
% 'NumActivePlots' -- The number of active plot objects to be created. Each
% plot will plot a column of data versus the first column of data
% Default -- [] No plots are created
%
% 'DataFile' -- Name of the data file to use to send to the Arduino over
% the serial port. If a file is specified then it is assumed
% that data will be sent to the Arduino, nothing else is required
%
%
% Output Arguments
%
% outData -- A matrix of the numerical values sent from the Arduino to the
% Serial Port
%
% Written by Mark Thompson 8/2020
% ECTET Department
% College of Engineering Technology
% Rochester Institute of Technology
%
% Revisions A
%
% 9/8/2020 Modified code to improve receiving a NaN in the data
%
p = inputParser;
% If the device is a PC then the Com Port is numeric. If it is
% a MAC then the COM port is a string
if ispc
defaultComPort = 3;
p.addParameter('ComPort', defaultComPort, @isnumeric);
else
defaultComPort = [];
p.addParameter('ComPort',defaultComPort, @ischar);
end
defaultBaudRate = 9600;
defaultNumReadSamples = [];
defaultReadyString = '%Arduino Ready';
defaultPortTimeOut = 1; % 1 second port time out
defaultEchoData = true; % Default to echo the RX String
defaultActivePlot = []; % Default active plotting to false
defaultGraphDelay = 1; % Default delay between updates to the graphs
defaultDataFile = ''; % Default file name
p.addParameter('BaudRate', defaultBaudRate, @isnumeric);
p.addParameter('NumReadSamples', defaultNumReadSamples, @isnumeric);
p.addParameter('ReadyString', defaultReadyString, @ischar);
p.addParameter('PortTimeOut', defaultPortTimeOut, @isnumeric);
p.addParameter('EchoData', defaultEchoData, @islogical);
p.addParameter('NumActivePlots', defaultActivePlot, @isnumeric);
p.addParameter('GraphDelay', defaultGraphDelay, @isnumeric);
p.addParameter('DataFile', defaultDataFile, @ischar);
p.parse(varargin{:});
inputArgs = p.Results;
comPort = inputArgs.ComPort;
baudRate = inputArgs.BaudRate;
numReadSamples = inputArgs.NumReadSamples;
readyString = inputArgs.ReadyString;
portTimeOut = inputArgs.PortTimeOut;
echoData = inputArgs.EchoData;
nActivePlots = inputArgs.NumActivePlots;
graphDelay = inputArgs.GraphDelay;
sendDataFileName = inputArgs.DataFile;
TAB = char(9);
% If the active plot is enabled, instantiate and object and create the
% figure
if ~isempty( nActivePlots )
%
% Create the number of active plots and place in an array of handles
%
% Create the figures
%
for iPlot = 1:nActivePlots
hPlot(iPlot) = ActivePlot('GraphTitle',sprintf('Graph %2d',iPlot) );
hPlot(iPlot).CreateFigure;
hPlot(iPlot).xLabelStr = 'Sample';
end
end
% Instantiate the Arduino Serial Port Object
hArd = ArduinoSerial('ComPort', comPort,...
'BaudRate',baudRate,...
'ReadyString', readyString,...
'PortTimeOut', portTimeOut);
% Open the serial port to the Arduino
hArd.OpenSerial;
% Arduino will look for a g character to start. Read the port and see if
% the correct string has been sent.
hArd.WaitForReady;
% Send the 'g' character to start reading data
hArd.WriteString('g');
% Read data from the serial portr
dataAvailable = true; % Set data available flag to true
contReadSamples = true; % Set to continue to read samples
firstLine = true;
rowIndex = 1;
outData = [];
graphPointCount = 0;
sendDataFlag = false; % Flag to indicate if there is data to be sent
sendDataCounter = 1;
% If there is a file to be sent then load the file
if ~isempty( sendDataFileName )
% Load the file
sendSerialData = load( sendDataFileName );
% The file has a variable named breathingData which has at least two columns
% The first column is the sample number. The second column breathing data
%
% There may be multiple columns of data?
%
dataMx = sendSerialData.breathingData;
% Reshape the breathing data so that it is in one column only. Don't
% use the sample number column
[nSendSamples,nColumns] = size(dataMx);
inputData = reshape( dataMx(:,2:end), nSendSamples * (nColumns-1) , 1 );
sendDataFlag = true;
end
while dataAvailable && contReadSamples
% If the send data flag is true then grab the next value and send it
% over the port
if sendDataFlag
% Get the next value from the input matrix and send it
sendValue = inputData( sendDataCounter );
hArd.WriteNumeric( sendValue );
sendDataCounter = sendDataCounter + 1;
end
% Idle while waiting for data in the buffer
% Start the timer
dataAvailable = hArd.WaitForData;
if dataAvailable
rxString = hArd.ReadArduino;
if ~isempty( rxString )
% Echo the serial data to the MATLAB command window
if echoData
if ~isempty(rxString)
% Check for an end of line character. If there is not one
% then add it
if strcmp(rxString(end), newline) || strcmp(rxString(end), char(13))
fprintf('%s',rxString);
else
fprintf('%s\n',rxString)
end
end
end
% Split the string by TABs
dataString = strsplit( rxString, TAB );
% Convert each cell in the split to a double. If it is the
% first data received and is a NaN then assume it is a header
% and don't put it in the data array. If its a NaN but not
% the first row then put a NaN in the plot array
for iCell = 1:length(dataString)
% Flag to indicate if the row has any data in it. If it
% does the row index will be incremented
dataWrittenInRow = false;
% Convert the string in the cell to a numerical value. Check
% if it is NaN
numericValue = str2double( dataString{iCell} );
% If this is the first string of data and is a NaN then assume it is a header
% and don't put it in the data array. If its a NaN but not
% the first row then put a NaN in the plot array
if ~( isnan( numericValue ) && firstLine )
outData( rowIndex, iCell ) = numericValue; % Its a number put a number in the array
dataWrittenInRow = true;
end
end
% Check if any valid data written in the row. If so then
% increment the row index value. Clear the firstData flag
if dataWrittenInRow
rowIndex = rowIndex + 1;
firstLine = false;
end
% Compare the the number of rows of data written to the input
% argument NumReadSamples. If it is equal then stop reading
% from the port. The NumReadSamples is empty keep reading
% indefinitely
if ~isempty( numReadSamples )
if rowIndex > numReadSamples
contReadSamples = false;
end
end
% If the active plot is enabled then update the trace
if ~isempty( nActivePlots )
if ~isempty( outData )
% Check the GraphDisplay parameter to see if it is
% time to update the display
graphPointCount = graphPointCount + 1;
if graphPointCount >= graphDelay
% Update the display
for iPlot = 1:nActivePlots
hPlot(iPlot).UpdatePlot( [outData(:,1), outData(:,iPlot+1)] );
end
graphPointCount = 0;
end
end
end
% Clear the firstLine flag
firstLine = false;
end
end
end
% Close the serial port
hArd.ClosePort;
% Prompt user whether to save data
defaultAnswer = {'N'};
response = inputdlg('Save Data to File? [N]','Save File',1,defaultAnswer);
if ~isempty(response) % Was CANCEL pressed?
if strcmpi( response(1), 'y')
[fileName, pathName ] = uiputfile({'*.mat'},'Select File Name');
if fileName ~= 0
save(fullfile(pathName, fileName),'outData');
end
end
end

View file

@ -0,0 +1,150 @@
// OPEN NEW ARDUINO SKETCH.
// CLICK IN THIS TEXT BOX. CTRL-A, CTRL-C.
// CLICK IN SKETCH. CTRL-A, CTRL-V.
// Lab2_handout.ino
// created by: Clark Hochgraf 2015
// modified by: David Orlicki, October 1, 2017
// modified by: David Orlicki, September 7, 2019
// modified by: Mark Thompson, September 8, 2020
// Outputs 3 bit DAC resistor network drive.
// Reads/displays ADC samples of LM61 sensor output.
// Reads/displays averaged subsamples of LM61 sensor output.
// Reads/displays dithered-averaged subsamples of LM61 sensor output.
// Calculates running mean and standard deviation of samples.
#include <MsTimer2.h>
#include <SPI.h>
const int TSAMP_MSEC = 100; // senor: 100, sim: 10
const int DAC0 = 3, DAC1 = 4, DAC2 = 5, LM61 = A0, VDITH = A1;
const int NUM_SUBSAMPLES = 160, NUM_SAMPLES = 1024;
volatile boolean sampleFlag = false;
int tick = 0;
float sample, mean, stdev;
//*******************************************************************
void setup()
{
configureArduino();
// This line tells MATLAB that the Arduino is ready to accept data
Serial.println("%Arduino Ready");
//Serial.println("Enter 'g' to go .....");
// Wait until MATLAB sends a 'g' to start sending data
while (Serial.read() != 'g'); // spin until 'g' entry
MsTimer2::set(TSAMP_MSEC, ISR_Sample); // Set sample msec, ISR name
MsTimer2::start(); // start running the Timer
} // setup()
//*******************************************************************
void loop()
{
syncSample();
sample = analogRead(LM61);
//sample = analogReadAve();
//sample = testDAC(tick);
// sample = analogReadDitherAve();
// sample = 185-0*tick/32.0+2*sin((tick/32.0)*TWO_PI);
// recurseStats1(sample, mean, stdev);
// recurseStats2(sample, mean, stdev);
displayData();
if (++tick >= NUM_SAMPLES) while(true); // spin forever
} // loop()
//*******************************************************************
float analogReadAve(void)
{
float sum = 0.0;
for (int i = 0; i < NUM_SUBSAMPLES; i++) sum += analogRead(LM61);
return sum/NUM_SUBSAMPLES; // averaged subsamples
}
//*******************************************************************
float testDAC(int index)
{
digitalWrite(DAC0, (index & B00000001)); // LSB bit mask
digitalWrite(DAC1, (index & B00000010));
digitalWrite(DAC2, (index & B00000100)); // MSB bit mask
return analogRead(VDITH);
}
//*******************************************************************
float analogReadDitherAve(void)
{
return 0.0; // stub function return
}
//*******************************************************************
void recurseStats1(float smpl, float &mean, float &stdev)
{
// Smith algorithm adjusted for tick start at 0
static float sum, sumSquares;
if (tick == 0)
{
mean = smpl;
sum = smpl;
sumSquares = smpl*smpl;
}
else
{
sum += smpl;
sumSquares += smpl*smpl;
mean = sum/(tick+1);
float var = (sumSquares - (sum*sum)/(tick+1))/tick;
stdev = sqrt(var);
}
}
//*******************************************************************
void recurseStats2(float smpl, float &mean, float &stdev)
{
// B. P. Welford algorithm adjusted for tick start at 0
static float oldMean, runSumVar, oldRunSumVar;
mean = 0.0;
stdev = 0.0;
}
//*******************************************************************
void displayData(void)
{
if (tick == 0) Serial.print("\nn\tsample\n");
Serial.print(tick); Serial.print('\t');
Serial.print(sample); Serial.print('\n');
}
//*******************************************************************
void syncSample(void)
{
while (sampleFlag == false); // spin until ISR trigger
sampleFlag = false; // disarm flag: enforce dwell
}
//*******************************************************************
void configureArduino(void)
{
pinMode(DAC0,OUTPUT); digitalWrite(DAC0,LOW);
pinMode(DAC1,OUTPUT); digitalWrite(DAC1,LOW);
pinMode(DAC2,OUTPUT); digitalWrite(DAC2,LOW);
analogReference(DEFAULT); // DEFAULT, INTERNAL
analogRead(LM61); // read and discard to prime ADC registers
Serial.begin(115200); // 11 char/msec
}
//*******************************************************************
void ISR_Sample()
{
sampleFlag = true;
}

View file

@ -0,0 +1,25 @@
#ifndef MsTimer2_h
#define MsTimer2_h
#ifdef __AVR__
#include <avr/interrupt.h>
#elif defined(__arm__) && defined(TEENSYDUINO)
#include <Arduino.h>
#else
#error MsTimer2 library only works on AVR architecture
#endif
namespace MsTimer2 {
extern unsigned long msecs;
extern void (*func)();
extern volatile unsigned long count;
extern volatile char overflowing;
extern volatile unsigned int tcnt2;
void set(unsigned long ms, void (*f)());
void start();
void stop();
void _overflow();
}
#endif

Binary file not shown.