|
many people built LED based vu meter, using analog solutions that tend to be complicated.
since many mcus have built-in adc, why not build a mcu-based vu meter?
here is an example of a vu meter built using a pic driving a 16x2 LCD module.
the mcu will adc two channels, left and right, and display the output, as two bars of characters, on a 16x2 lcd display module.
the output is user-defined and in this particular case logarithmic: the first character lights up at 1mv of input, and the 14 characters light up at about 5v, for a dynamic range of about 40db, far greater than most vu meter.
(原文件名:lcd vu meter.JPG)
here is the code
#include <htc.h>
#include <string.h>
#include "delay.h"
//#include "lcd_4bit.h"
#include "lcd_3wi.h"
__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);
#define sleep() asm("sleep") //put the mcu to sleep
#define ADC_CH0 (1<<0) //adc on an0
#define ADC_CH1 (1<<1) //adc on an1
#define ADC_L ADC_CH0 //adc_left on adc0
#define ADC_R ADC_CH1 //adc_right on adc1
#define LCD_Line_L LCD_Line0 //L ch on lcd_line0
#define LCD_Line_R LCD_Line1 //R ch on lcd_line1
#define LED_PIN (1<<5) //led on GPIO1
#define PA_SET(bits) PORTA |= (bits); //set bits on porta
#define PA_CLR(bits) PORTA &=~(bits); //clear bits on porta
#define PA_FLP(bits) PORTA ^= (bits); //flip bits on porta
#define DLY_Main_Loop 50 //main loop delay of 10ms
#define LCD_char 0x05 //lcd char
#define LCD_char_B ' ' //lcd background
const unsigned char str_L[]="L: ";
const unsigned char str_R[]="R: ";
const unsigned char str_0[]="16F684 VU Meter1";
const unsigned char str_v[]="version 0.1-1234";
const unsigned int val2ln[]={
1, 2, 3, 5, 8, 14, 25, 42,
71, 121, 207, 352, 600, 1022};
unsigned char vRAM[17];
typedef struct {
unsigned char char_code;
unsigned char char_pattern[8];
} LCD_CGRAM_CHAR;
const LCD_CGRAM_CHAR LCD_CGRAM_CHAR_PATTERN[]={
{0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, //empty background
{1, {0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00}}, //1 vertical line
{2, {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}}, //2 vertical line
{3, {0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x00}}, //3 vertical line
{4, {0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x00}}, //4 vertical line
{5, {0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x00}}, //5 vertical line = block / bar
{6, {0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00}},
{7, {0x1f,0x1f,0x1f,0x1b,0x1f,0x1f,0x1f,0x00}}
// {7, {0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00}}
};
void lcd_cgram_init(void) { //initiate the cgram
unsigned char i, j;
for (i=0; i<8; i++) {
// lcd_cgram_write(LCD_CGRAM_CHAR_PATTERN);
lcd_write(0x40+(LCD_CGRAM_CHAR_PATTERN.char_code*8), 0); //send the command
for(j=0;j<8;j++)
lcd_write(LCD_CGRAM_CHAR_PATTERN.char_pattern[j], 1); //send the bigmap data
}
}
void adc_init(void) { //initialize the adc
// ADCON0 = config_mask;
ADCS2=0, ADCS1=1, ADCS0=0; //adc running at fosc/32
ADFM=1; //adc results right justified
VCFG=0; //Vdd as reference voltage
ADON=0; //adc off
}
unsigned int adc_read(unsigned char ch){//read adc
ANSEL |= ch; //select the adc channel, and adc at fosc/32
// TRISIO |= ch; //turn it as input
CHS1=(ch-1) >> 1; //select the channel
CHS0=(ch-1);
ADON=1; delay_us(1); //turn on the adc
GODONE=1;
while (GODONE) continue; //wait for the adc to complete;
ADON=0; //turn off the adc
return (ADRESH<<8) + ADRESL;
}
void ultoa(char *s, unsigned long ul, unsigned char length) { //convert unsigned long to a string, 3 dps
unsigned char i;
i=length;
do {
// if (i==(length-3)) s[i--]='.';
s[i--]=ul % 10 + '0';
ul = ul / 10;
} while (ul);
}
void mcu_init(void) {
CMCON0=0x07; //turn off comparators;
//TRISIO=0b11; //input on GPIO0, all others digital output;
ANSEL=0x00; //all ports gpio
IRCF2=1, IRCF1=1, IRCF0=0; //4Mhz
}
void bar_display(unsigned char lcd_line, unsigned int val) { //display a value
unsigned char i;
unsigned char vstr[17];
for (i=0; i<14; i++) { //fill the lcd array
if (val<val2ln) vstr=LCD_char_B;
else vstr=LCD_char;
}
// ultoa(vstr, val, 10);
lcd_display(lcd_line+2, vstr);
}
void main(void)
{
//unsigned char temp=0, gSPad[9], i;
unsigned int i;
//unsigned int val_L, val_R;
mcu_init(); //initialize the mcu
lcd_init(); //initialize the lcd
lcd_cgram_init(); //initialize the cgram for 8 user definable characters, 0..7
adc_init(); //initialize the adc
strcpy(vRAM, str_0); lcd_display(LCD_Line0, vRAM);
strcpy(vRAM, str_v); lcd_display(LCD_Line1, vRAM); delay_ms(50);
strcpy(vRAM, str_L); lcd_display(LCD_Line_R, vRAM);
strcpy(vRAM, str_R); lcd_display(LCD_Line_L, vRAM);
// sleep();
while (1){
//TODO Auto-generated main function
bar_display(LCD_Line_L, adc_read(ADC_L));
bar_display(LCD_Line_R, adc_read(ADC_R));
delay_us(DLY_Main_Loop); //delay some time
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
如果天空是黑暗的,那就摸黑生存;
如果发出声音是危险的,那就保持沉默;
如果自觉无力发光,那就蜷伏于牆角。
但是,不要习惯了黑暗就为黑暗辩护;
也不要为自己的苟且而得意;
不要嘲讽那些比自己更勇敢的人。
我们可以卑微如尘土,但不可扭曲如蛆虫。
|