1. Understand how the generator works

advertisement
1. UNDERSTAND HOW THE GENERATOR WORKS
First of all, I had to learn more about the generator. In fact; it is very simple: a small
magnet is placed into a tube. Around this tube is a coil. Each time the magnet slides inside the
coil, then every turn of the coil are under magnet’s flux, which is moving. Therefore, a
differentiated flux is created by walking. According to Faraday’s Law of Electromagnetic
Induction, there is a induced voltage in the coil, V(t), which expression is :
N
d (t )
V (t )   i
with N the number of turns.
dt
i 1
As we consider here that the magnet has a constant velocity v, which is not far from
the reality on small length (about 2centimeters/0.8inches), this relation becomes:
N
d ( xi )
V (t )  v  
dx i
i 1
Thanks to Matlab simulation, we can predict the magnetic flux distribution generated
by a specific magnet in space; therefore the induced voltage can be foretold. This previous
model stuck literally to the reality, so that previous people who worked on this project have
chosen to keep this analytical approach. The coil’s length has been calculated for an optimum
way of harvesting energy trough a differentiate magnetic flux from these data.
The problem was then to build a model of the movement of the magnet sliding into the
coil… Some measurements with accelerometers have been made in the heel of a shoe during a
walk to see on what force fields the magnet is under, and try to predict the movements and the
speed of the magnet during a walk-that obviously depends on every walker’s profile.
2.
SEEING HOW MUCH POWER CAN BE EXPECTED
a. From our wearable generator
Induced voltage waveform is as follow (in an heel during a step ~1s):
Voltage level can be heavily improved but in disregard of overall performances. We
can easily reach near 12V by increasing number of copper wire turns. Nonetheless, by doing
this, we increase also the global length of this copper wire, which implies an internal
resistance increasing that slashes output power.
Using diodes with mega Schottky barrier effect enables to design a better rectifier
stage that is more efficient. I found from Philips® such diodes with a very low Vdrop (average
130mV) when forward current is 10mA. Therefore, rectified voltage keeps suitable level and
losses are reduced.
P(t ) 
RL  (V (t )  Vdrop ) 2
N
with V (t )   Vi cos(i t  i ) 
( RL  RS ) 2
i 0
from Fourier’s transformée of real movement induced voltage.
Finding capacitors with low internal series resistance enables also to keep charged
these capacitors longer than common ones and reduces losses in a dobler rectifier stage.
The next section was a search throughout the web about devices consumption, in
sleeping mode and in active mode. This part was also the occasion to learn how to find further
information and other details by myself thanks to the Internet.
b. For wearable devices consumption:
Devices that can’t be powered by our generator:
Devices that potentially could be powered by our generator:
3. DESIGN A RECTIFIER STAGE
Now that we have an optimized generator, this induced voltage is still in alternative.
However, our demonstrator needs a direct current supply to properly work.
Previous works highlight that a rectifier stage such as a doubler stage provides the best
output power. I have made some simulations under PSPICE from real measurements of the
induced voltage during a walk that confirms these previous works. I have compared this result
to other rectifier stage (like quadrupler, full wave & half wave rectifiers, etc…)
Therefore, diodes with very low drop voltage and small in size capacitors (but with big
capacity, too) are required. Previous researches have shown than the BAT series from
Philips® have the lowest Vdrop, but I found some diodes better than previously found. They
use the Schottky barrier effect to reach their performances: at 10mA, the Vdrop, or Vforward, is
only 130mV whereas the BAT series have at the same current more than 300mV!
Actually, as the dobler don’t provide us up to 5V alone, we can’t use any amplifier or
other logical gates which are very common to regulate his kind of regulation. This dobler
provides us with a Direct Current that can be regulated by a Step-Up/Down DC-DC
Converter, just like the MAX1672 component, which allows us to input from continuous 1.8V
and have an output up to 11V (with a lower current, there is obviously no generation of power
at all, only conversion). Please, be sure not overpass 3.5V to supply the N RF24E1: it can only
stand 3.6V maximum. On the other hand, voltage must be upper than 1.9 to enable a properly
work to be done by RF transmission. See MAX1672 Datasheet for further details.
4. DESIGN A DEMONSTRATOR
I found some different ideas for demonstrators: obviously, as generator is placed in
shoe’s heel, it must be linked with the foot: a pedometer application sounds great both for
Maeve and me.
When we have seen partnership between Nike® and Ipod®, we also want to make a
similar project; by designing a radio frequency transmitter sensor in Nike® shoes that
synchronizes with Ipod while running, a small program can show distances, average speed
and similar data from running.
To make our own Radio Frequency (RF) pedometer system, it was envisaged trying
several options. First of all, logic gates that realize a step counter which value is sent by a RF
transmitter sounded great. However, our voltage level was not enough to perform this kind of
technologies. We have also understood that if we can have the induced voltage waveform
transmitted too, it should be good for future enhancement of our system.
This new challenge brought us to a second choice, which was using a very low power,
very low voltage microprocessor from Texas Instruments®: MSP430 which works from 1.8V.
An issue was we must include RF transmitter that fits the MSP430 voltage range considering
power consumption. Most of those I found during my researches weren’t efficient enough
according to this parameter (actually only one found could do the job: CHIPCON1000 from
Texas Instruments®).
That’s why I considered a global component which features microcontroller, Analog
to Digital Converter, and RF transmitter; two components are a cut above the rest:
RFPIC12F675 (which also integrate an EEPROM) and NRF24E1 (working with an external
EEPROM).
According to datasheet, RFPIC12F675 is not as good as NRF24E1 considering power
issue; moreover, NRF24E1 is a transceiver, that means it could perform both transmission and
reception. We found this particularity interesting for future enhancements of our
demonstrator. Number of analog inputs was a great advantage.
Therefore, I choose, with Maeve’s validation, this NRF24E1 component, even if some
drawback existed: for instance, small size and unusual package (QFN 36) for this component
were going to present some problems for soldering. Availability was also an issue. See further
details in the third part on third section of present report.
5. BUILDING DEMONSTRATOR
Actually, I have just followed the schematic given by Nordic Semiconductor to build
both the RF transmitter and RF Receiver, but some parameters result of personal choices. I
explain why some choices have been made.
I work with a crystal frequency of 16 MHz; this option was selected between ranges of
4 up to 20 MHz for datasheet mentions that this specific frequency gives best over all
performances. Moreover, it enables us to transmit by Shockburst™ method (power saving).
Principle:
Here is the current consumption with 2 proceeding ways.
The ShockBurst™ technology uses on-chip FIFO to clock in data at a low data rate
and transmit at a very high rate thus enabling extremely power reduction. You gain access to
the high data rates (1 Mbps) offered by the 2.4 GHz band without the need of a costly, highspeed microcontroller (MCU) for data processing. By putting all high speed signal processing
related to RF protocol on-chip, the nRF24El offers the following benefits:
• Highly reduced current consumption
• Lower system cost (facilitates use of less expensive microcontroller)
• Greatly reduced risk of 'on-air' collisions due to short transmission time
NRF24E1 uses a bootstrap loader, that requires the use of a generic 25XX320
EEPROM. I have chosen 25AA320 memories from Microchip® as they work from 1.8V up
to 5.5V at a maximum frequency of 1MHz, which could be useful as our generator only
provides little power (range of few mW).
I have also opted for some low current diodes to display on output pins their high or
low state. As NRF24E1 can only provide 0.5mA under 2V on each digital output pins, I
preferred use these diodes, even if their lightness will be weak, because it’s more convenient
than use oscilloscope to watch high or low state.
I want also warn for future works that specifications for Crystals are not well
followed, because the used ones have been found directly from boxes in laboratory; however,
I think they should work (very few characteristics are not fulfilled and this should not matter)
but perhaps they will need to be changed. The same can be said about capacitors (4.7pF,
which are not Tantallum); the convenient package size was the parameter I’ve considered for
choosing the ones used in this circuit.
6. PROGRAMMING NRF24E1:
The very first thing to begin with is to know well the different registers used by this
component to work properly. Some of them are well initialised for our application, so that we
don’t need to change their hexadecimal values. Some have 8 bits, other only 2. Registers’
values imply different behaviours from microcontroller.
Good values for our demonstrator are entered in registers thanks to a C-language (c
file with h file), and then translated by a compiler (Keil compiler was used) in series of
hexadecimal bytes (hex file), which is the basic language for microcontroller. This hex file is
sent by EEPROM Programmer into memory (EEPROM).
NRF24E1 only has a small internal ROM which contains a bootstrap loader that
downloads (thanks to Serial Peripheral Interface on Port 1 P1) program contained in external
EEPROM to 256 byte data internal RAM that is erased each power reset. To make our Intel
hex file compiled suitable for this bootstrap loader, we need to add 3 byte heading our file:
data rate speed plus crystal frequency used,
offset to start of our program,
number of 256 byte blocks in our program.
Before programming, I had to go through datasheet of NRF24E1 with a fine-tooth
comb to understand how does work this microcontroller which is based on an 8051 structure.
The red spots lay a stress on subsystems used in my program code:
Here are listed some special function registers (SFR) used for my application.
Their places in NRF24E1 memory are specified in the h file, so as simply bits definition too:
Analog to Digital Converter: ADCCON, ADCSTATIC, ADCDATAH, ADCDATAL
Serial Peripheral Interface: SPICLK, SPI_DATA, SPI_CTRL
Radio Transceiver:
RADIO, PWR_UP, CS, CE, DR1, CK_CTRL, CKCON
Interruption:
TCON, TH0, TMOD, EXIF, EIE, EIP, EICON
Display:
P0, P0_ALT, P0_DIR, P1, P1_ALT, P1_DIR
a. Analog Digital Converter (ADC)
Registers:
ADCCON:
Bit(s)
Name
7
DIFFM
6
SLEEP
5
CLK8
4-2
ADCBIAS
1-0
ADCRES
ADCSTATIC:
Bit(s)
7
6
5
4
3-0
(in red, my selection)
Function
Enable differential measurements: 0 or 1
Set A/D converter in a reduced power mode
ADCCLK frequency = CPU clock/32:0 or clock/8:1
No need to change for NRF24E1 operation
11 select resolution: 12-bit.
Name
CSTARTN
ADCRUN
NPD
EXTREF
Function
Toggle High -> Low -> High to start A/D conversion.
Set high to have the A/D converter run continuously 0
Set to 0 to put A/D converter in power down state
Select reference for A/D converter
0: Use internal reference. 1: Use external pin AREF
ADCSEL upper
For n=0…7,
ADCSEL=n
willofselect
input pin AINn
ADCDATAH:
bits of converted
value
AIN voltage
ADCDATAL:
lower bits and flags if under/overflow occurred
Reference for ADC is software selectable between AREF input and an internal 1.22V
reference. Here, internal reference is chosen, so that AREF input is ignored.ADC has 9 inputs.
Typically used in start/stop mode, sampling time is then under software control. It is software
configured to perform 12 bit conversions. ADC may also be used in differential mode with AIN0
used as inverting input and one of the other inputs used as noninverting. Unused input 8, enables
software to monitor NRF24E1 supply voltage by converting internal VDD/3 with AREF pin.
There are only 4 used; 2 modes are
used; one in differential way (yellow), other in
‘classic’ way (pink or green). This enables user
to measure voltage on coil whereas the coil is
connected to rectifier stage (see InitADC(n)
and InitDiffAdc() functions in Appendix 10).
Best resolution (12bits) and frequency
(Clk/8) are selected thanks to the ADCCON &
ADCSTATIC registers. Continuous running of
ADC is not used due to the power issue.
Sampling performances are slashed by data
sending frequency. Conversion is made by
Conversion() function. It consists on a toggle
on the CSTARTN pin. ReadADC(n) function
reads converted value, which is stored in two
8bits registers ADCDATA(H&L). Four lower
bits give conversion indications (overflow …).
A flag (IE2 in EXIF register) highlights that the signal was sampled successfully.
Waiting for this flag set high is needed before reading the values. So this bit must be reset
low, once it goes high.
b. Serial Peripheral Interface(SPI)
Registers for Serial Peripheral Interface with EEPROM and Radio Transceiver:
SPICLK:
divider factor from CPU clock to SPI clock (2)
SPI_DATA: SPI data input/output (used for read/write) (8)
SPI_CTRL: how is used the SPI (with radio or port1)
(2)
00
10
The SPI is very useful to control EEPROM (handled by bootstrap loader on P1) or to
control RADIO transceiver (via CPU data bus). According to recommendations in datasheet, I
have used this SPI to link both transceiver and microcontroller.
Whenever SPI_DATA (8 bits) register is written to, a sequence of 8 pulses is started
on SCK, and the 8 bits of SPI_DATA register are clocked out on SDO with msb first.
Simultaneously 8 bits from SDI are clocked into SPI_DATA register. Ouput data is shifted
on negedge SCK, and input data is read on posedge SCK.
This means that we perform as well a reading as a writing thanks to SPI. Data in
SPI_DATA register before SPI transaction is written in selected peripheral. In the same time,
data in SPI_DATA register after SPI transaction is read from the peripheral.
When the 8 bits are done, SPI_READY interrupt (fifth bit of EXIF register) goes
active, and the 8 bits from SDI may be read from SPI_DATA register. The EXIF.5 bit must be
cleared before starting another SPI transaction by writing to SPI_DATA register again.
SCK, SDO and SDI may be external pins or internal signals, as defined in SPI_CTRL
register: P1 port or Radio port are selected to be connected with SP Interface.
You have certainly quoted that there are a lot of delays in a SPI transmission.
However, to ensure that data has well been sent, 6th bit of EXIF (flag bit) is expected in high
state and then must be cleared before ending SPI transaction.
c. Radio Transmission
There is only one register for the Radio Transceiver: RADIO. Actually, I use, in this
register, some bits which have each a specific use:
powering NRF2401:
PWR_UP
(8th bit)
enable transmission mode: CE
(7th)
enable configuration mode: CS
(4th)
when reception ends:
DR1
(3rd)
link with SCK from SPI:
CLK1
(2nd)
link with SDO and SDI:
DATA
(1st)
Transceiver part of the circuit has identical functionality to the NRF2401, which is a
radio transceiver for the world wide 2.4-2.5 GHz ISM band integrated in the NRF24E1. This
transceiver consists of a fully integrated frequency synthesizer, a power amplifier, a
modulator and two receiver units. Output power and frequency channels and other RF
parameters are easily programmable by RADIO register. It can perform 2 different signals
reception simultaneously (thanks to DuoCeiver™ technology, unused here) and be accessed
through an internal parallel port and / or an internal SPI. NRF2401 subsystem can be
programmed using a simple 3-wire interface where the data rate is decided by the speed of the
CPU.
It is more convenient to use the built-in SPI interface to do the most common
transceiver operations as RF configuration and
SPI signal
SPI_CTRL=10
ShockBurst™ RX (reception) or TX (transmission).
CS (active high)
CE for ShockBurst™
The radio port is connected in different ways to the
CS for Configuration
SPI hardware when SPI_CTRL is '10', which is the
SCK
nRF2401/CLK1
case (when SPI_CTRL is 'Ox', all radio pins are
SDI
nRF2401/DATA
connected directly to their respective port pins).
SDO
nRF240l/DATA
Data Ready
DR1
All configuration of the NRF2401 subsystem is done via a 3-wire interface (CS, CLKl
and DATA) to a single configuration register. The configuration word can be up to 18 bytes
long. The configuration bits (DATA) must be clocked (by CLKl) into NRF2401 subsystem,
with msb first, while CS=1. No more than 18 bytes may be downloaded. CE and CS may not
be high at the same time. Setting one or the other decides whether configuration or active
mode is entered.
When a transmission occurs, a flag bit that informs the transmission is well ended is
set high on both channels (DR1 & DR2; DR: Data Ready). These flags can be software
programmed as interrupts to the microcontroller (or polled via a GPIO port). Here, I only use
a unique channel (use of DR1 and CLK1 bits only).
RF current consumption is only 10.5 mA in TX mode (output power -5dBm) and 18
mA in RX mode. For power saving the transceiver can be turned on / off under software
control (thanks to PWR_UP & CE bits).
Initialising transmission:
Each time PWR_UP is set high, datasheet explains user must wait 3ms; that’s why
there is a delay function in my program.
CS bit is used to configure the transceiver at each powering up.
Mode
PWR UP CE CS
Active (RX/TX)
1
l
0
Configuration
1
0
1
Stand by
1
0
0
Power down
0
X X
The configuration word (144 bits) enables transceiver subsystem to handle the RF
protocol and is loaded into the configuration register. Configuration blocks are as follows:
Bit
Length
Function
Value (hexa or bit)
143:120
24
Reserved for testing
0x8E081C: (default)
119:112
8
Length of data payload section RX channel 2
0x20: (unused)
111:104
8
Length of data payload section RX channel 1
0x20: (32 bits sent)
103:64
40
Up to 5 byte address for RX channel 2
0x00000000: (unused)
63:24
40
Up to 5 byte address for RX channel 1
0x000000BB: (1 byte*)
23:18
6
Number of address bits (both RX channels).
001000: (8)
17
1
8 or 16 bit CRC
1: 16bits CRC
16
1
Enable on-chip CRC generation/checking.
1: CRC enabled
15
1
Enable two channel receive mode
0: only one receiver used
14
1
Communication mode (Direct or ShockBurst™)
1: Shockburst™ enabled
13
1
RF data rate ( 1 Mbps requires 16MHz crystal)
1: 1Mbps
12:10
3
Crystal frequency
011: 16MHz
9:8
2
RF output power
00: -20dB
7:1
7
Frequency channel (arbitrary choice)
0000010: 2402MHz
0
1
RX or TX operation
0 for transmitter (1 receipter)
This configuration word is shifted in MSB first on positive CLKl edges.
*Suggestions for addresses use to have less false detection: equal bytes are not recommended. Level
shifted only one time could be detected in noise. First byte of address should not start with 0x55 or
OxAA as this may be interpreted as part of preamble, causing address mismatch for the rest of the
address.
Transmitting and receiving packets:
ShockBurst™ transmit sequence: (CPU interface pins: CE, CLKl, DATA)
1.
When the application CPU has data to send, set CE high. This activates
NRF2401 on-board data processing.
2.
The address of the receiving node (RX address) and payload data is clocked
into the NRF2401 subsystem. The application protocol or CPU sets the speed < 1Mbps (ex:
10kbps).
3.
CPU sets CE low; this activates a ShockBurst™ transmission.
4.
ShockBurst™:
• RF front end is powered up
• RF package is completed (preamble added, CRC calculated)
• Data is transmitted at high speed (1 Mbps configured by software).
PREAMBLE
ADDRESS
PAYLOAD
CRC
Preamble is 8 bits in length and is dependent of the first address bit and is
automatically added or removed to the data packet
1st ADDR-BIT is 1: 01010101
or
0: 10101010
8 to 40 bits length, automatically added and removed from received packet
Data to be transmitted: size is 256 bits minus the following: (Address + CRC).(32)
The CRC is optional (8 or 16 bits length) and automatically added or removed
ShockBurst™ receive sequence: (CPU interface pins: CE, DR1, CLK1 and DATA)
1.
Correct address and size of payload of incoming RF packages are set when
nRF2401 subsystem is configured to ShockBurst™ RX.
2.
To activate RX, set CE high.
3.
After 200µs settling, NRF2401 subsystem is monitoring the air for incoming
communication.
4.
When a valid package has been received (correct address and CRC found),
nRF2401 subsystem removes the preamble, address and CRC bits.
5.
NRF2401 subsystem notifies (interrupts) the CPU by setting the DRl pin high.
6.
CPU may set the CE low to disable the RF front end (low current mode).
7.
The CPU will clock out just the payload data at a suitable rate (ex. 10 kbps).
8.
When all payload data is retrieved NRF2401 subsystem sets DRl low again,
and is ready for new incoming data package if CE is kept high during data download. If the
CE was set low, a new start up sequence can begin.
d. Interruption
There are several registers used in this section:
to control internal clock:
CKCON
to control timer 0:
TCON
TMOD
TH0
to enable interruption:
IE
EXIF
EIE
EIP
Aim of interruption here is to have a time indication, to realize a chronometer
function. Using RC oscillator is not recommended in datasheet, because its frequency is said
very inaccurate (1 to 5 KHz). Yet, this option should be the best as regards as the power
consumption. However, a program correcting this inaccuracy is “heavy” to be implemented in
our embedded final product, but still realisable.
I have explored option to use timer 2 (16 bits) in capture mode so that software has an
accurate base of time that could be read at any time… but this option has a consequence:
using a multiplex in/output on pin 4 (P1.0), which is still not very easy to encode. I found the
last option more convenient to program. Before I present how this chronometer function is
made, let me introduce you some information about timers.
The NRF24E1 includes three timer/counters (Timer 0, Timer 1 and Timer 2). Each
timer/counter can operate as either a timer with a clock rate based on the CPU clock or as an
event counter clocked by the t0 pin (Timer 0), tl pin (Timer 1). or the t2 pin (Timer 2). These
pins are alternate function bits of Port 0 and 1 as this: t0 is P0.5. tl is P0.6 and t2 is P1.0. Each
timer/counter consists of a 16-bit register that is accessible to software as three registers:
Timer i(1/2/3): TLi (8-bit) and THi(8-bit). Timer 0 can operate in four modes, as controlled
through TMOD and TCON registers:
13-bit timer/counter (mode 0)
16-bit timer/counter (mode 1)
8-bit counter with auto-reload (mode 2)
Two 8-bit counters (mode 3)
Another way to have a good timing is to use a simple 8bits counter, for instance timer
0, and set it in auto-reload mode; this is configured by the value of TMOD register
programmed as follow TMOD |=0x02.
Bit
Function in TMOD Register
TMOD.7 GATE Timer 1 gate control.
TMOD.6 C/T Counter/Timer 1 select.
TMOD.5-4 Timer 1 mode select bit 1.
TMOD.3 GATE When GATE = 0, Timer 0 will clock only when TR0=1, regardless of int0_n state.
TMOD.2 Counter/Timer select. When C/T = 0. Timer 0 is clocked by CPU_clk/4 or CPU_clk/12,
depending on the state of T0M (CKCON.3). When C/T = 1. Timer 0 is clocked by t0 pin.
TMOD.1-0 10 Mode 2 : 8-bit counter with auto-reload
In mode 2, timer is configured as an 8-bit counter, with automatic reload of start value.
The LSB register (TL0) is the counter, and MSB register TH0 stores the reload value.
However, in mode 2, when TL0 increments from 0xFF, value stored in TH0 is reloaded into
TL0. Therefore, initial value must be placed in TH0 register (8 bits).
Actually, initial value is calculated so that overflow occurs every 0.1µs (e.g.
0x7A=122) and stored in TH0 register (8bits). The 133 increases from this value (until
255=28-1) take place each 12 cycles clock as configured by T0M bit (at a low level in register
CKCON). This can be made by line code: CKCON &= ~0x08
Bit
CKCON.7,6
CKCON.5
CKCON.4
CKCON.3
CKCON.2-0
Function CKCON Register
Reserved
T2M - Timer 2 clock select.
TIM-Timer 1 clock select.
T0M - Timer 0 clock select. when T0M = 0. Timer 0 uses CPU_clk/l2
(Reserved)MD2, MD1, MD0, I strongly recommend do not touch
To be logic with previous choice made in TMOD with the GATE bit, IT0 bit should
be set low. To start the timer, TF0 bit must be set high (TCON |=0x10).
Bit
Function TCON Register
TCON.7-6 TF1 and TR1 for timer 1.
TCON.5 TF0 Timer 0 overflow flag. Set to 1 when Timer 0 overflows and cleared
when the CPU vectors to the interrupt service routine.
TCON.4 TR0 Timer 0 run control. Set to 1 to enable counting on Timer 0.
TCON.3-2 IE1 and IT1 interruption for timer 1.
TCON. 1 IE0: In level-sensitive mode, software cannot write to IE0.
TCON.0
IT0=0, nRF24El detects int0_n as a low level (level-sensitive mode).
When an overflow occurs, that is to say every 0.1µs (Timer increment is independent
of main program, e.g. every 12 CPU clock), TF0 flag bit is automatically set high. It is seen as
an interruption on timer 0. Interruption occurs each 0.1µs; where fast changes on global
timing variables by software enable to have access to accurate timer data.
NRF24E1 supports the following interrupt sources:
Interrupt signal Description
TF0
Timer 0 interrupt (counter overflow)
int2
Internal ADC EOC (end of AD conversion) interrupt
int3
Internal SPI_READY interrupt (finished transaction)
int4
Internal RADIO.DR1 interrupt (a packet is ready from receiver 1)
When an enabled interrupt occurs, CPU vectors to the address of the Interrupt Service
Routine (ISR) associated with that interrupt. Then, CPU executes the ISR to completion
unless another interrupt of higher priority occurs (there is only one interruption here). Each
ISR ends with a return from interrupt instruction. After executing this, CPU returns to the next
instruction that would have been executed if the interrupt had not occurred.
An ISR can only be interrupted by a higher priority interrupt. That means ISR for a
low-level interrupt can be interrupted only by a high-level interrupt. CPU always completes
the instruction in progress before servicing an interrupt. If instruction in progress is RETI. or a
write access to any of the IP, IE, EIP, or EIE Registers, CPU completes one additional
instruction before servicing the interrupt.
Interrupt
TF0
int2
int3
int4
Description
Natural Priority
(lowest number gives highest priority)
Timer 0 interrupt
2
ADC_EOC interrupt 8
SPI_READY interrupt 9
RADIO.DR1 interrupt 10
Interrupt Vector
0x0B used
0x43 unused
0x4B unused
0x53 unused here
EA bit (IE.7: 8th bit in IE register) is a global enable for all interrupts. When EA = 1,
each interrupt is enabled/masked by its individual enable bit. When EA = 0, all interrupts are
masked. Next table provides a summary of interrupt sources, flags, enables, and priorities.
Interrupt
TF0
int2
int3
int4
Description
Timer 0 interrupt
ADC_E(nd)O(f)C(onversion) interrupt
SPI_READY interrupt
RADIO.DR1 interrupt
Flag
TCON.5
EXIF.4
EXIF.5
EXIF.6
Enable
IE.l=1
EIE.0
EIE.1
EIE.2
Control
IP.1
EIP.0
EIP.1
EIP.2
IE must be initialized at 10000010 (0x82), which is made by this command: ‘IE |=0x82’.
This table shows why these flags are raised:
Bit
Function of these Interrupt Flag
TCON.5 TF0 Timer 0 overflow flag. Set high automatically when Timer 0 overflows and
cleared when the CPU vectors to the interrupt service routine.
EXIF.6
IE4 = 1 indicates that a rising edge was detected on the RADIO.DR1 signal.
EXIF.5
IE3 = 1 highlights that SPI module is ready for a new command
EXIF.4
IE2 = 1 rising edge detected in ADC_EOC signal, (End of conversion)
These bits must be cleared by software. Setting them high in software generates an interrupt,
if enabled.
All flag bits that don’t need to be interrupt-enabled are listed below:
Bit
Function
EIE.2 EX4 EX4 = 0 disables interrupt 4 (RADIO.DR1).
EIE.l EX3 EX3 = 0 disables interrupt 3 (SPI_READY).
EIE.0 EX2 EX2 = 0 disables interrupt 2 (ADC_EOC).
The interruption handling
Sending RF packets:
In C, interrupt number is given by (0x0B-3)/8, where 0x0B is the interrupt vector address.
Here are some lines of interruption code:
void Chronometer(void) interrupt 1 {
Interruption occurs only when TF0 overflow counter 0 flag bit has rised, i.e. every 100µs.
TF0 = 0; to set low the interrupt flag (overflow in timer 0): it enables another interruption.
j++; to count how many times interruptions occurred. Then, we enter in a conditional action.
If the packet is ready to transmit and an interrupt occurred there is 600µs ago,
if((j%6==0)&&(ready==1)){CE=0;} then, we can start data transmission in ShockBurst®.
Every 600µs, a packet is expected to be sent, so that Sample Frequency is >1620Hz (that
means our waveform of induced voltage on coil is well sampled, see 3§ below).
Step detection:
Now, we have to detect steps made by walker, if a step has been counted and the time
difference between the time on counted step (timeflag) and now (j) is neg:
if ( (flag == 1) && (j < timeflag) ) {if( (timeflag-j) == 3000 ) Then if the step was counted
300ms ago, we can come back to 'listen' another step detection {flag = 0;} (flag highlights
ability to detect a step or not: while flag is rise, no step is detected. 300ms correspond to the
while during over or underflows can occur. If a step has been counted and the time difference
between the count and now is pos and there was 300ms ago:
if ((flag == 1) && (j>timeflag)) {if((j-timeflag) == 3000) Then, we come back listening:
{flag=0;}} So that disability to detect step lasts only 300ms after a previous step was detected.
Time basis:
To have an accurate basis of time, here are the lines:
if (j==10000)
//j is an integer (can go up to 65535): 10000*100µs=1s
{
j=0;
//every second we begin again another cycle
time++;
//seconds are incremented
if(time==59)
//when we reach a new minute (time is a char: 255 max)
{time=0;}}}
//we start another one from the beginning
This interruption can be used to send periodically (every 600µs) data (address and
payload). A study of a typical signal generated by the shoe-generator (voltage on one coil)
during a walk reveals that the maximal frequency of the signal is about 820Hz. A good
sampling of this signal is assured if the sampling frequency is about twice this max frequency
(1640Hz). Actually, sending data every 600µs is enough to receipt the waveform of this
signal. This could be easily achieved by including the control of the bit of sending (CE). By
this way, if the counter of the number of interruptions is a multiple of 6 (which happens each
600µs) and if the data to send are ready (which is filled for the complete code controlling the
ADC and the Serial Peripheral Interface executes itself in less than 500µs), then the order of
data sending is given.
The whole interrupt code is entirely executed in few hundred of nanoseconds, so that
the accuracy of the timing is maintained. Therefore, time is a reliable variable that gives us a
good timing indication.
e. Display
To display data sampled on the receiver part, some input/output port are used. Here are their
related registers: Port 0:
P0
P0_ALT
P0_DIR
I do not use Port 1.
The device has 1 general purpose
input (DIN0) and 10 general purpose bidirectional pins. These are by default
configured as GPIO pins controlled by the
ports P0 (DIO2 to DIO9) and P1 (DIO0,
DIO1, DIN0) of the microcontroller. Most
of the GPIO pins can be used for multiple
purposes under program control. Alternate
functions include two external interrupts, a
SPI master port, three enable/count signals
for the timers and a PWM output.
The NRF24E1 have two IO ports fully
bi-directional CMOS and the direction of
each pin is controlled by a _DIR and an
_ALT register.
During period of internal reset
(regardless of whether or not the clock is
running), all the port pins are configured as
inputs. When program execution starts, the
DIO ports are still configured as inputs and
program will need to set _ALT and/or _DIR
register for pins that should be used as outputs.
Name
Function
P0
Port 0, pins DI09 to DI02
P0_DIR For each bit of Port 0; 0: Output, 1: Input
P0_ALT Select alternate functions for each pin of P0
Unused here.
P0_ALT and P0_DIR control P0 port function in that order
of priority. If the alternate function for port P0.n is set (by
P0_ALT.n = 1) the pin will be input or output as required by
the alternate function (UART, external interrupt, timer
inputs
or
PWM
output.
Pin
P0.0 (DI02)
P0.1 (DI03)
P0.2 (DI04)
P0.3 (DI05)
P0.4 (DI06)
P0.5 (DI07)
P0.6 (DI08)
P0.7 (DI09)
P0_DIR= 0x81
P0.0
In
P0.1
Out
P0.2
Out
P0.3
Out
P0.4
Out
P0.5
Out
P0.6
Out
P0.7
In
7. WITH COMPONENTS
Ordering
The main component was not provided by the lab’s supplier, e.g. Farnell®.
Nordic Semiconductor, which is the company that makes this component, was in holyday
during all July. Therefore, we have some delays expected. Finally, I have made some
research on Internet and try a company in UK, CLERE Company, that was found in
partnership with Nordic…so that, I email them to see if they stock the NRF24E1. The
answer was positive, and I ask them for sending some samples, and they answer very fast.
What I’ve learned from this issue is, sometimes, you must do it by yourself,
without going trough classic hierarchy when it is necessary, in order to have a faster
service.
Soldering
As the main component, the NRF24E1 is really small (6mm squared and 36 pins),
I had some problem to sold it. We refer to the CEL Company, located at Tuam, (10km
from Galway) to sold it. Once again, important delays have been encountered
8. WITH UNITS
They also have a tendency to measure in inches instead in centimetres, to talk
about Fahrenheit degrees instead Celsius. They mix all these unities: we can’t know if
our interlocutor is going to use one or another unity. I found very useful a ruler in which
both of the unities (cm; inches) are quoted.
II.
BIBLIOGRAPHY
Websites:
www.farnell.com
www.nordicsemi.no
www.rare-earth-magnets.com
www.forcefieldmagnets.com
www.mmcmagnetics.com
Books / Publications:
Demonstrator Circuit for Wearable Power Generators (Ronan Crowley)
Electromagnetic generators for Power Harvesting (Maeve Duffy & Damien Carroll)
Design of a Wearable Generator with a Magnetic Core (Nicolae Popa & Maeve Duffy)
Demonstration of Wearable Power Generator (Damien Carroll & Maeve Duffy)
Energy Harvesting from Passive Human Power (Loreto Mateu)
Energy Harvesting from Passive Human Power (Loreto Mateu)
Review of Energy Harvesting Techniques and Applications for Microelectronics
(Loreto Mateu & Francesc Mol)
Human Generated Power for Mobile Electronics (Thad Starner & Joseph A. Paradiso)
Theoretical aspects concerning the calculus possibilities of magnetic fluid core coils
(Nicolae Popa)
Shoe-mounted Piesoelectrics (IEEE MICRO May/June 2001)
Datasheets:
NRF24E1 from Nordic®
NRF2401 from Nordic®
25AA320 from Microchip®
EECS0HD104 from Panasonic®
MAX1672 from Maxim®
PMEG1020EA from Philips®
HLMP-D155 from Agilent Technologies®
APPENDIX 9: C-LANGUAGE BASES
Memory allocation:
Registers or bits addresses are defined in h file (given by the constructor), so that we can
use their name as they appear in datasheet directly in program code.
Operations:
Or (|) and And (&) operations are made bit per bit which rules are
1&1=1,
1|1=1,
1&0=0,
1|0=1,
0&1=0,
0|1=1,
0&0=0,
0|0=0
Bit complementary (~) operation: 0 becomes 1 and vice-versa
Specific operator %: x%y will return the rest of Euclidian division of x by y
Translation of n bits from the left to the right hand side: (bits to translate) << n.
Conversely, use >> from the right to the left hand side translation.
Allocation is made by only one sign =: for instance, TH0=0x7A; puts the hexadecimal
value 0x7A into TH0 register. (TH0 bits will be 01111010=0x7A)
i++; is the same than i=i+1(increasing); n--; is the same than n=n-1(decreasing); (here, i
and n are variables).
Conversion hexadecimal/binary:
Every 4 bits gathered made 1 hex value. In hex, we write from 0-9, then from 10
to 15 translated by A to F, A=10, B=11 … F=15.
1011=1*23+0*22+1*21+1*20=1*8+0*4+1*2+1*1=8+2+1=11=B (max, 15: F, min 0: 0)
Conversely, 0xE9=1110(E)1001(9)=11101001.
Some examples you will find in my program.
TMOD |=0x02; implies that TMOD=TMOD | 0x02;, here only 2nd bit of TMOD is set
high, others are unchanged.
CKCON &= ~0x08; is the same that CKCON=CKCON & (~0x08); and ~0x08 is 0xF7,
here we only change (set low) the 4th bit of CKCON.
TCON |=0x10; only the 5th bit is set high, others are unchanged.
IE |=0x82; only 8th and 2nd bits are set high here, others are unchanged.
Sometimes, 2 operations are needed:
ADCCON &= ~0x80; set low last bit of ADCCON,
ADCCON |= 0x80; and then set high this same last bit. This allows us to make a toggle
on CSTARTN pin to start a sample on ADC input.
Cleverer:
ADCSTATIC &= 0x1C; we keep previous values of 5th, 4th and 3rd bits and set others
low.
ADCSTATIC |= 0xA3; then, even if we don’t know actual value of 3 bits (5th,4th, and 3rd)
we can change other bits which are in the same register without changing these specific 3
bits. This operation is named a masking, because some bits are voluntarily ‘hidden’ for
changing.
Special actions:
Conditional actions:
Using if(condition) {action1;} else{action2;} will execute action1 only if condition is
verified otherwise action2 will be done.
A condition is often a double equality: x == y; if x has the same value than y,
therefore this expression is seen as a ‘Boolean 1’, so that condition is verified. If y is 1,
condition could be simply x. In a condition, logical signs like & (and) or | (or) are
repeated twice. Parentheses are used to show which operations has priority. Condition x
different from y is written: x != y.
Waiting sequences:
do{action;}while(condition); will execute action until condition is not anymore verified.
while(condition); will do nothing until condition is verified.
Loops:
for(i=1;i<N;i++) {action;} will execute N times action; i is initialized at 1(i=1) and is
incremented (i++) until i<N is no more verified.
Beware with infinite loops:
do{…} while(1) or for(;;){…} will generate infinite sequences, which can cause abortion
of program or incorrect end of thread when there are not handled carefully.
Functions:
C file is organized in functions in which local variables are defined (to be used
only in this function). In head of file are defined global variables, which can be accessed
by any function in C file.
Program will start executing main function (in which must be placed all
initialisations), defined as follow: void main(void) {…}
Interrupt function is special, because it will stop program, execute itself, then
return to execute program from where it was stopped.
Parameters:
Functions can have parameters, so that when they are used with a specific
parameter, specific actions will be done.
Function can return only one result, which type is defined in function definition:
int(eger on 16 bits), char(acter ASCII on 8 bits), long (32 bits) (unsigned or not, depends
on memory reservation that the µcontroller can afford)… void is the term used when
there is no parameter returned by (or given to) function.
Words are predefined in c language: typedef struct will enable building several
kinds of variables in only one. ‘txconf’ is, for instance, a character (n) and a vector (buf)
of characters (see Appendix 10). Accessing to one or other variable is made by selecting
txconf.n or txconf.buf. Then, to access nth variable in txconf.buf vector, txconf.buf[n] will
do the job
APPENDIX 10: PROGRAM CODE FOR TRANSMITTER
pedo2.c
1
/* Author: LE BORGNE Guillaume Training period : summer 2006
2
* After initializing the ADC on desired channels 0-3, radio & timer, the transmitter
3
* reads the ADC and transmits the read data (16bits) : differential value AIN1-AIN0 & AIN2 (& AIN3)
4
* Then it sends the time elapsed since the program has started, thanks to Shockburst method...
5
***********************************************************************************/
6
#include <reg24e1.h>
//definition of SFR registers
7
#define ADDR_INDEX 5
// Index to address bytes in RFConfig.buf
8
#define ADDR_COUNT 1
// Number of address bytes
9
//definition of the structure of word configuration
10
struct RFConfig
11
{
unsigned char n;
12
unsigned char buf[9];};
13
typedef struct RFConfig RFConfig;
14
//Configuration word for transmitter
15
const RFConfig txconf ={ 9,
16
0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x23, 0x6c, 0x04};
17
// data2 width / data1 width / ADDR2 / ADDR1 /ADDR width/CRC16bits enabled /only 1 channel /Shockburst
@16Mhz /Power@-20dB/ Channel 2.402GHz/transmission
18
//avoid "A" & "5" in address
19
20
8its 21
22
23
24
25
26
27
28
unsigned int j=0,timeflag=0;
unsigned char time,ready,flag;
//an int can go up to 65535 16bits
//a char can go up to 255
//interrupt handle each 100us during = 0.1us
void Chronometer(void)
interrupt 1
{//the interrupt number is given by (0x0B-3)/8, where 0x0B is the interrupt vector address
TF0 = 0;
//clear the interrupt flag overflow in timer 0
j++;
if ( ( (j%6) == 0) && (ready == 1) )
{CE = 0;}
//start of data to transmit in ShockBurst
every 600us
29
if ( (flag == 1) && (j < timeflag) )//if a step has been counted and the time
difference between the count and now is neg
30
31
32
{
if( (timeflag-j) == 3000 ) //and there was 300ms ago
{flag = 0;}}
//come back to 'listen'
if ((flag == 1) && (j>timeflag))
//if a step has been counted and the time
difference between the count and now is pos
33
34
35
36
37
38
39
40
42
43
44
45
47
48
{
if((j-timeflag) == 3000)
{flag=0;}}
//and there was 300ms ago
//come back to 'listen'
//so that the global Sample Frequency is >1620Hz (signal of voltage induced well sampled)
if (j==10000)
{
j=0;
time++;
//sec incrementing
if(time==59)
{time=0;}}}
//we described every sec 41
void Delay100us(volatile unsigned char n)
{
unsigned char i;
while(n--)
for(i=0;i<35;i++);} 46
unsigned char SpiReadWrite(unsigned char b)
{
EXIF &= ~0x20;
// Clear SPI interrupt (ie IE3 cleared: flag showing
data was sent or received)
49
50
51
52
SPI_DATA = b;
//
while(IE3!=1);
while((EXIF & 0x20) ==
return SPI_DATA;}
// Move byte to send to SPI data register
//SPI ready (EXIF & 0x20=IE3)
0x00);
// Wait until SPI has finished transmitting
//access to in or out put data 53
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
79
80
void Init(void)
{
unsigned char g;
//interrupt init
IE |= 0x82;
//interrupt from timer0 enabled
//init radio
PWR_UP = 1;
Delay100us(30);
SPICLK = 0x00;
SPI_CTRL = 0x02;
// Turn on Radio
// Wait > 3ms
// Max SPI clock (XTAL/8)
// Connect internal SPI controller to Radio
//settings for the transmitter
CS = 1;
Delay100us(0);
for(g=0;g<txconf.n;g++)
{SpiReadWrite(txconf.buf[g]);}
CS = 0;
//enable configuration mode
//sending configuration word to the transmitter
//disable configuration mode
//done for each power up (reset of all data)
//init timer 0 in auto reload mode(2), CPU/12 clock
//133*7.5e-7=100us therefore an incrementation of 133 from 122= 0111 1010 =0x7A
CKCON &= ~0x08;
//T0M=0 => CPU/12 clk
TMOD |= 0x02;
//Gate=0, C/T=0, Mode 2
TH0 = 0x7A;
//initial value @ 122
TCON |= 0x10;
//set TR0 high : timer 0 starts
}//TF0 will set high each time timer 0 will be in overflow and causes an interruption 78
void InitADC(unsigned int c)
{
if (c==2) {ADCCON = 0x22;}
// Analog Input=2, NPD=1, ADCRUN=0,
EXTREF=0
81
if (c==3) {ADCCON = 0x23;}
EXTREF=0
82
//
if (c==4) {ADCCON = 0x24;}
EXTREF=0 ...
83
//
if (c==7) {ADCCON = 0x27;}
84
85
86
87
88
ADCSTATIC &= 0x1c;
ADCSTATIC |= 0x23;}
// Analog Input=3, NPD=1, ADCRUN=0,
// Analog Input=4, NPD=1, ADCRUN=0,
// Analog Input=7, NPD=1, ADCRUN=0, EXTREF=0
// we don't touch to these 3bits
// highest frequency (2) and 12bits resolution(3)
void InitDiffADC(void)
{// Analog Input=0 will be used as inverting input, others as non-inverting inputs, NPD=1, ADCRUN=0,
EXTREF=0
89
ADCCON = 0x21;
// Analog Input=1, NPD=1, ADCRUN=0,
EXTREF=0
90
91
ADCSTATIC &= 0x1c;
// we don't touch to these 3bits
ADCSTATIC |= 0xA3;}
// highest frequency & differential mode enabled
(A) and 12bits resolution(3) 92
93
void Conversion(void)
//on start, CSTARTN is high initially
94
{
ADCCON &= ~0x80;
// Start.. (toggle on CSTARTN)
95
ADCCON |= 0x80;}
// ..new conversion
96
//
IE2 will set automatically high at the end of the conversion 97
98
unsigned char ReadADC(unsigned int w)
99
{
unsigned char b;
100
while((EXIF & 0x10) == 0);
// Wait until ADC conversion is complete :
ADC_EOC signal
101
102
103
EXIF &= ~0x10;
if(w==0) {b = ADCDATAH;}
if(w==1) {b = ADCDATAL;}
...)
104
return b;} 105
// Clear ADC completion bit
// Read ADC data 8bits MSB
// Read ADC data 4bits LSB + details(overflow,
112
113
114
115
116
117
118
void main(void)
{
unsigned char a,k,step;
j = 0;
timeflag = 0;
time = 0;
ready = 0;
flag = 0;
//interrupt counter
//sensibility of counting steps
//number of second to be send
//go for shockburst sending data
// say if an increment of step number is
possible
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
step=0;
Init();
for(;;)
{
if(ready==0)
{Delay100us(1);
InitDiffADC();
//interrupt radio timer init
// Wait ~100us
// differential measurement AIN1 - AIN0
//between only 1 coil ends before rectifier stage Vmax<Vref=1.22V
Conversion();
// Loading of data to transmit
CE = 1;
// transmission mode on
Delay100us(0);
for(k=0;k<ADDR_COUNT;k++) // Start with the address of the receiver:
{SpiReadWrite(txconf.buf[ADDR_INDEX+k]);}
a = ReadADC(1);
// Read ADC LSB
// Step counting
if(((a & 0x01)==1)&&(flag==0)) // if there is under or over flow and the
possibility of counting steps
135
136
{
step = 0x01;
flag=1;
// detect one step
// become insensible detecting a step
timeflag=j;}
// record of time
during 300ms
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Continue loading of data to transmit
InitADC(3);
Conversion();
a = ReadADC(0);
SpiReadWrite(a);
a = ReadADC(1);
k = time;
a &= 0xF0;
a |= ((k & 0x38)>>2);
a |= step;
step = 0;
SpiReadWrite(a);
InitADC(2);
Conversion();
a = ReadADC(0);
SpiReadWrite(a);
a = ReadADC(1);
a &= 0xF1;
a |= ((k & 0x07)<<1);
SpiReadWrite(a);
ready = 1;}}}
// measure AIN3; diffm disabled
// Read ADC MSB
// loading
// Read ADC LSB
//time doesn't have to change
// reset 4 bits LSB
// change 3 bits
// say if there is or not one more step
// count only one time the step once detected
// loading
// measure AIN2; diffm disabled
// Read ADC MSB
// loading
// Read ADC LSB
// the other bits are low
// change 3 bits of a
// loading
// address & payload ready
APPENDIX 11: PROGRAM CODE FOR RECEIVER
receiver2.c
1
2
/* Author: LE BORGNE Guillaume Training period : summer 2006
* After initializing the the port P0 & the radio, the receiver has the read data (48bits) thanks to Shockburst
method...*/
3
#include <reg24e1.h>
//definition of SFR registers
4
#define ADDR_INDEX 5
// Index to address bytes in RFConfig.buf
5
#define ADDR_COUNT 1
// Number of address bytes
6
//definition of the structure of word configuration
7
8
9
10
11
12
13
14
struct RFConfig
{
unsigned char n;
unsigned char buf[9];};
typedef struct RFConfig RFConfig;
//Configuration word for receiver
const RFConfig rxconf ={ 9,
0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x23, 0x6c, 0x05};
// data2 width / data1 width / ADDR2 / ADDR1 /ADDR width/CRC16bits enabled /only 1 channel /Shockburst
@16Mhz /Power@-20dB/ Channel 2.402GHz/reception
15
unsigned int step=0;
//an int can go up to 65535
16
17
18
19
20
21
22
23
24
unsigned char sec,m,h;
//a char can go up to 256
void Delay100us(volatile unsigned char n)
{
unsigned char i;
while(n--)
for(i=0;i<35;i++);}
unsigned char SpiReadWrite(unsigned char b)
{
EXIF &= ~0x20;
// Clear SPI interrupt (i.e. IE3 cleared : flag
showing data was sent or received)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
SPI_DATA = b;
//
while(IE3!=1);
while((EXIF & 0x20) == 0x00);
return SPI_DATA;}
// Move byte to send to SPI data register
//SPI ready (EXIF & 0x20=IE3)
// Wait until SPI has finished transmitting
//access to in or out put data
void Init(void)
{
unsigned char b;
//port 0
P0_DIR = 0x81;
P0 &=0x81;
//pin 0.1 to P0.6 output
//init radio
PWR_UP = 1;
Delay100us(30);
SPICLK = 0x00;
SPI_CTRL = 0x02;
// Turn on Radio
// Wait > 3ms
// Max SPI clock (XTAL/8)
// Connect internal SPI controller to Radio
//settings of the receiver
CS = 1;
Delay100us(0);
for(b=0;b<rxconf.n;b++)
{SpiReadWrite(rxconf.buf[b]);}
CS = 0;}
unsigned long ReceivePacket()
{
unsigned char a,b,c;
unsigned long x;
CE = 1;
//configuration enabled
//configuration disabled
//receive mode enabled
51
52
53
54
while(DR1 == 0);
x = SpiReadWrite(0);
a = SpiReadWrite(0);
b = SpiReadWrite(0);
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
c = SpiReadWrite(0);
CE = 0;
//received mode disabled
x <<= 8;
x = x | a;
x <<= 8;
// stack
x = x | b;
x <<= 8;
x = x | c;
sec = (((x & 0x000E0000)>>13)|(x & 0x0000000E));
sec >>= 1;
if (sec==59)
{
sec=0;
m++;
//Time increment
if (m==60)
{
m=0;
h++;}}
if (((x & 0x00010000)>>15) == 2);//Step increment
{step=step+2;}
return x;}
//data received
//waiting end of data flux
//reading data flux
void Receiver(void)
{
unsigned long y;
do
{
y = ReceivePacket();
//start of checking that can be removed later
do
{
if ((P0>>7)==1)
{P0 = (y & 0xFC000000)>>25;}
else
{P0 = (y & 0x03F00000)>>19;}
y = ReceivePacket();
}while(sec<20);
do
{
if( (P0>>7)==1 )
{P0 = (y & 0x0000FC00)>>9;}
else
{P0 = (y & 0x000003F0)>>3;}
y = ReceivePacket();
}while(sec<40);
//MSB AIN3
//LSB AIN3
//receipt payload bits
//MSB AIN2
//LSB AIN2
//receipt payload bits
//end of checking part that can be removed later
do
{
if((P0>>7)==1)
{P0 = (sec << 1);}
else
{P0 = ((step & 0x3F) << 1);}
y = ReceivePacket();
}while(sec!=59);
}while(1);}
//time elapsed displayed
// number of steps displayed
//receipt payload bits
105
106
107
108
109
110
111
void main(void)
{
sec = 0;
step = 0;
m = 0;
h = 0;
Init();
Receiver();}
APPENDIX 12: NRF24E1 H FILE
/* -----------------------------------------------* reg24e1.h Header file for the Nordic VLSI
nRF24E1 2.4Ghz RF transceiver with embedded
8051 compatible microcontroller. $Revision: 1 $
* ------------------------------------------------ */
#ifndef __REG24E1_H__
#define __REG24E1_H__
/* BYTE Registers */
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
sfr
P0
TCON
TMOD
TH0
CKCON
EXIF
IE
IP
EICON
EIE
EIP
P0_DIR
P0_ALT
RADIO
ADCCON
ADCDATAH
ADCDATAL
ADCSTATIC
SPI_DATA
SPI_CTRL
SPICLK
CK_CTRL
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
0x80;
0x88;
0x89;
0x8C;
0x8E;
0x91;
0xA8;
0xB8;
0xD8;
0xE8;
0xF8;
0x94;
0x95;
0xA0;
0xA1;
0xA2;
0xA3;
0xA4;
0xB2;
0xB3;
0xB4;
0xB6;
/* BIT Registers */
/* TCON */
sbit
sbit
sbit
sbit
TF0
TR0
IE0
IT0
=
=
=
=
TCON^5;
TCON^4;
TCON^1;
TCON^0;
/* IE */
sbit EA
= IE^7;
/* RADIO */
sbit PWR_UP
sbit CE
sbit CS
sbit DR1
sbit CLK1
sbit DATA
#endif
=
=
=
=
=
=
RADIO^7;
RADIO^6;
RADIO^3;
RADIO^2;
RADIO^1;
RADIO^0;
APPENDIX 13: SCHEMATICS FOR TRANSMITTER
APPENDIX 14: SCHEMATICS FOR RECEIVER
Download