gtuner.c


1
/*
2
  Jesper Hansen <jesperh@telia.com>
3
  
4
  This program is free software; you can redistribute it and/or
5
  modify it under the terms of the GNU General Public License
6
  as published by the Free Software Foundation; either version 2
7
  of the License, or (at your option) any later version.
8
9
  This program is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with this program; if not, write to the Free Software Foundation, 
16
  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17
18
*/
19
20
21
22
/*
23
24
  Simple Digital Guitar Tuner
25
  ---------------------------
26
  version 1.0    2001-02-12  jesper
27
  
28
29
30
  PIN assignements on the 2323 (ATiny 45)
31
  
32
  PB0    High LED
33
  
34
  PB1    Input pin
35
  
36
  PB2    Low Led
37
38
*/
39
40
41
#include <avr/io.h>
42
#include <avr/interrupt.h>
43
44
#define sbi(p,n)        (p) |= (1<<(n))
45
#define cbi(p,n)        (p) &= ~(1<<(n))
46
#define outp(p,n)       (p) = (n)
47
#define inp(p)          (p)
48
49
#define F_CPU        4000000          // CPU clock frequency
50
#define PRESCALER      64          // CPU prescaler value
51
52
#define BASE_FREQUENCY    (F_CPU/PRESCALER)  // counter frequency  
53
54
#define TUNING_FORK_A    440.0        // "base" A
55
#define NOTE_DIFF      1.05946309436    // the 12'th root of 2
56
57
#define E_STRING  164.81            // top string (1)
58
#define A_STRING  220.00
59
#define D_STRING  293.66
60
#define G_STRING  391.99
61
#define B_STRING  493.88        
62
#define EH_STRING  659.26            // bottom string (6)
63
64
// The guitar note span
65
//  # # #  # #  # # #  # #
66
//EF G A BC D EF G A BC D E
67
//1    2    3    4 * 5    6
68
//
69
70
unsigned int Center_Count[] =
71
{
72
  BASE_FREQUENCY/EH_STRING,      // High E  94,80        262,11
73
  BASE_FREQUENCY/B_STRING,      // B       126,5489
74
  BASE_FREQUENCY/G_STRING,      // G       159,44
75
  BASE_FREQUENCY/D_STRING,      // D       212,83
76
  BASE_FREQUENCY/A_STRING,      // A       284,09
77
  BASE_FREQUENCY/E_STRING,      // Low E   379,22
78
};
79
80
unsigned int Transition_Count[] =
81
{
82
  BASE_FREQUENCY/(B_STRING+(EH_STRING-B_STRING)/2),  // E to B     
83
  BASE_FREQUENCY/(G_STRING+(B_STRING-G_STRING)/2),    // B to G
84
  BASE_FREQUENCY/(D_STRING+(G_STRING-D_STRING)/2),    // G to D
85
  BASE_FREQUENCY/(A_STRING+(D_STRING-A_STRING)/2),    // D to A
86
  BASE_FREQUENCY/(E_STRING+(A_STRING-E_STRING)/2),    // A to E
87
};
88
89
90
91
92
volatile unsigned char count_hi;  // overflow accumulator
93
94
//
95
//timer 0 overflow interrupt
96
//
97
SIGNAL(SIG_OVERFLOW0)  
98
{
99
  count_hi++;            // increment overflow count
100
}
101
102
//
103
//timer 1 overflow interrupt
104
//
105
SIGNAL(SIG_OVERFLOW1)  
106
{
107
  count_hi++;            // increment overflow count
108
}
109
110
//----------------------------------------------------------------------------
111
// Main Lupe
112
//----------------------------------------------------------------------------
113
114
115
int main(void) 
116
{
117
  unsigned int i; 
118
  unsigned int count;
119
  
120
121
 //------------------------------
122
 // Initialize 
123
 //------------------------------
124
125
  cbi(DDRB, 1);      // PB1 is input
126
  cbi(PORTB, 1);      // no pullups active
127
128
  
129
  sbi(DDRB, 0);      // PB0 is ouput, High LED
130
  sbi(DDRB, 2);      // PB2 is ouput, Low LED
131
132
133
  outp(TCCR1, 0b0111);    // set prescaler to f/64 (172.8 kHz @ 11.0592 MHz)
134
135
  sbi(TIMSK,TOIE0);    // enable interrupt on timer overflow
136
  asm volatile ("sei");  // global interrupt enable
137
138
 
139
140
 //----------------------------------------------------------------------------
141
 // Let things loose
142
 //----------------------------------------------------------------------------                        
143
144
145
  while (1)                // loop forever
146
  {
147
    count = 0;              // clear sample count
148
    loop_until_bit_is_set(PINB,1);    // wait for something to happen
149
150
    // got a high edge
151
    // start sampling
152
    
153
    outp(TCNT0, 0);            // clear counter     
154
    count_hi = 0;            // clear hi count
155
156
    
157
    // sample loop
158
    
159
    for (i=0;i<32;i++)
160
    {
161
      while (bit_is_set(PINB,1))    // ignore hi->lo edge transitions
162
      {
163
        if (count_hi > 80)      // skip if no edge is seen within
164
        {
165
          break;          // a reasonable time
166
        }
167
      }
168
169
      while (bit_is_clear(PINB,1))  // wait for lo->hi edge
170
      {
171
        if (count_hi > 80)      // skip if no edge is seen within
172
        {
173
          break;          // a reasonable time
174
        }
175
      }
176
177
      count += (count_hi << 8) + inp(TCNT0); // get counter value
178
      outp(TCNT0, 0);          // clear counter     
179
180
      if (count_hi > 80)        // skip if counter has accumulated a
181
      {
182
        break;            // too high value
183
      }
184
185
      count_hi = 0;          // clear hi count
186
    }
187
188
    // initially turn off both leds
189
    sbi(PORTB,0);
190
    sbi(PORTB,2);
191
192
    if (count_hi <= 80)          // if count is reasonable
193
    {
194
      count = count >> 5;        // average accumulated count by dividing with 32
195
  
196
      // now we have to find the correct string
197
            
198
      // go through transition frequencies
199
      
200
      for (i=0;i<(sizeof(Transition_Count)/sizeof(Transition_Count[0]));i++)
201
      {
202
        if (count < Transition_Count[i])
203
        {
204
          if (count-1 <= Center_Count[i])
205
                    {
206
                 // if count <= this string count
207
               cbi(PORTB,0);
208
          }
209
          if (count+1 >= Center_Count[i])      
210
          {
211
             // if count >= this string count
212
             cbi(PORTB,2);  
213
          }
214
        }
215
      }        
216
      
217
      // i now holds the string index
218
      
219
      // check the count for a match, allowing
220
      // 1 extra count "hysteresis" to avoid too 
221
      // much LED flickering
222
      
223
    }
224
  }
225
}