Last active
May 2, 2020 13:26
-
-
Save Electronza/0c3898b4d14900fd907f3bc5eed234ec to your computer and use it in GitHub Desktop.
EasyPIC v7: Talking breathalizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Project name: | |
Talking drunkometer (Demonstration of SmartMP3 board and Alcohol click) | |
* Description: | |
This project helps you get plastered | |
* Test configuration: | |
MCU: PIC18F45K22 | |
http://ww1.microchip.com/downloads/en/DeviceDoc/41412D.pdf | |
Dev.Board: EasyPIC7 | |
http://www.mikroe.com/easypic/ | |
Oscillator: HS-PLL 32.0000 MHz, 8.0000 MHz Crystal | |
ext. modules: Smartmp3 boardmp3 | |
http://www.mikroe.com/add-on-boards/audio-voice/smartmp3/ | |
2x16 lcd character displaylcd | |
Alcohol click | |
http://www.mikroe.com/click/alcohol/ | |
SW: mikroC PRO for PIC | |
http://www.mikroe.com/mikroc/pic/ | |
* NOTES: | |
- External power supply is highly recommended | |
- Put power supply jumper (J5) on the EasyPIC7 board in the 5V position. | |
- Configure SmartMP3 board for 5V operation | |
- Put PORTA switches in the middle (neutral) position. | |
- Put PORTD switches in the pull-down position and put Button Press | |
Level jumper J17 in the VCC position. | |
- Use RD0 and RD2 to increase volume for left and right channels, | |
RD1 and RD3 do decrease volume for left and right channels, respectively. | |
- MP3 file should have the following name : "trackxx.mp3". | |
- Put Alcohol click into mikroBUS socket #1 | |
*/ | |
#include "SmartMP3_routines.h" | |
// Lcd module connections | |
sbit LCD_RS_Direction at TRISB4_bit; | |
sbit LCD_EN_Direction at TRISB5_bit; | |
sbit LCD_D4_Direction at TRISB0_bit; | |
sbit LCD_D5_Direction at TRISB1_bit; | |
sbit LCD_D6_Direction at TRISB2_bit; | |
sbit LCD_D7_Direction at TRISB3_bit; | |
sbit LCD_RS at LATB4_bit; | |
sbit LCD_EN at LATB5_bit; | |
sbit LCD_D4 at LATB0_bit; | |
sbit LCD_D5 at LATB1_bit; | |
sbit LCD_D6 at LATB2_bit; | |
sbit LCD_D7 at LATB3_bit; | |
// button to start measurement | |
sbit BTN at LATE0_bit; | |
sbit BTN_Direction at TRISE0_bit; | |
// Treshholds for messages | |
// change according to your sensor sensitivity | |
// and to position of potentiometer on Alcohol click | |
// (needs some experiments) | |
unsigned int sober = 20; | |
unsigned int tipsy = 80; | |
unsigned int drunk = 150; | |
// Some variables | |
unsigned int i; // used in for loops | |
int refr; // refecence value | |
int alcohol; | |
unsigned char disp[8]; | |
void main() { | |
// Alcohol click is connected to RAd (analog) | |
ANSELA = 0x0C; // Set ADC on RA2 | |
TRISA = 0x0C; // Set RA2 as input | |
ANSELB = 0; // Configure PORTB pins as digital | |
ANSELC = 0; // Configure PORTC pins as digital | |
ANSELD = 0; // Configure PORTD pins as digital | |
ANSELE = 0; // Configure PORTE pins as digital | |
SLRCON = 0; // Configure all PORTS at the standard Slew | |
BTN_Direction = 1; // RE0 as input | |
Lcd_Init(); // Initialize Lcd | |
MP3_Init(); | |
// Setting the Alcohol click | |
ADC_Init(); // Initialize ADC | |
Lcd_Cmd(_LCD_CLEAR); // Clear display | |
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off | |
Lcd_Out(1,1,"Calibrate"); | |
for (i = 0; i < 150; i++){ | |
// start calibration | |
alcohol = ADC_Read(2); // Read RA2 | |
refr = ADC_Read(3); // Read RA3 | |
IntToStr ((alcohol-refr), disp); | |
Lcd_Out(2, 1, disp); | |
Delay_ms(100); | |
} | |
while(1){ | |
Lcd_Cmd(_LCD_CLEAR); // Clear display | |
Lcd_Out(1,1,"Press RE0"); | |
while(Button(&PORTE, 0, 1, 1)){ | |
// Wait for button press | |
} | |
Delay_ms(4000); | |
// RE2 pressed, start measuring | |
alcohol = ADC_Read(2); // Read RA2 | |
refr = ADC_Read(3); // Read RA3 | |
Lcd_Cmd(_LCD_CLEAR); // Clear display | |
if (alcohol < (refr + sober)){ | |
Lcd_Out(1,1,"Start drinking"); | |
MP3_Play("track01.mp3"); | |
} | |
if ((alcohol >= (refr + sober)) & (alcohol < (refr + tipsy))){ | |
Lcd_Out(1,1,"You need wine"); | |
MP3_Play("track02.mp3"); | |
} | |
if ((alcohol >= (refr + tipsy)) & (alcohol < (refr + drunk))){ | |
Lcd_Out(1,1,"Drink water"); | |
MP3_Play("track03.mp3"); | |
} | |
if (alcohol >= (refr + drunk)){ | |
Lcd_Out(1,1,"Go home!"); | |
MP3_Play("track04.mp3"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <built_in.h> | |
// CODEC V1053E connections | |
sbit MP3_CS_Direction at TRISC1_bit; | |
sbit MP3_CS at LATC1_bit; | |
sbit MP3_RST_Direction at TRISC2_bit; | |
sbit MP3_RST at LATC2_bit; | |
sbit DREQ_Direction at TRISC7_bit; | |
sbit DREQ at RC7_bit; | |
sbit BSYNC_Direction at TRISC6_bit; | |
sbit BSYNC at LATC6_bit; | |
// MMC module connections | |
sbit Mmc_Chip_Select_Direction at TRISC0_bit; | |
sbit Mmc_Chip_Select at LATC0_bit; // for writing to output pin always use latch (PIC18 family) | |
// Buttons for Left/Right Volume control | |
sbit BtnLeftDown_Direction at TRISD3_bit; | |
sbit BtnLeftUp_Direction at TRISD2_bit; | |
sbit BtnRightDown_Direction at TRISD1_bit; | |
sbit BtnRightUp_Direction at TRISD0_bit; | |
sbit BtnLeftDown at RD3_bit; | |
sbit BtnLeftUp at RD2_bit; | |
sbit BtnRightDown at RD1_bit; | |
sbit BtnRightUp at RD0_bit; | |
// VS1053E constants | |
const char WRITE_CODE = 0x02; | |
const char READ_CODE = 0x03; | |
// Module constants | |
const char SCI_BASE_ADDR = 0x00; | |
const char SCI_MODE_ADDR = 0x00; | |
const char SCI_STATUS_ADDR = 0x01; | |
const char SCI_BASS_ADDR = 0x02; | |
const char SCI_CLOCKF_ADDR = 0x03; | |
const char SCI_DECODE_TIME_ADDR = 0x04; | |
const char SCI_AUDATA_ADDR = 0x05; | |
const char SCI_WRAM_ADDR = 0x06; | |
const char SCI_WRAMADDR_ADDR = 0x07; | |
const char SCI_HDAT0_ADDR = 0x08; | |
const char SCI_HDAT1_ADDR = 0x09; | |
const char SCI_AIADDR_ADDR = 0x0A; | |
const char SCI_VOL_ADDR = 0x0B; | |
const char SCI_AICTRL0_ADDR = 0x0C; | |
const char SCI_AICTRL1_ADDR = 0x0D; | |
const char SCI_AICTRL2_ADDR = 0x0E; | |
const char SCI_AICTRL3_ADDR = 0x0F; | |
// Global Variables | |
unsigned long file_size; | |
const BYTES_2_WRITE = 32; | |
const BUFFER_SIZE = 448; | |
char mp3_buffer[BUFFER_SIZE]; | |
char volume_left, volume_right; | |
// Function writes one byte to MP3 SCI | |
void MP3_SCI_Write(char address, unsigned int data_in) { | |
BSYNC = 1; | |
MP3_CS = 0; // select MP3 SCI | |
SPI1_Write(WRITE_CODE); | |
SPI1_Write(address); | |
SPI1_Write(Hi(data_in)); // high byte | |
SPI1_Write(Lo(data_in)); // low byte | |
MP3_CS = 1; // deselect MP3 SCI | |
// wait until DREQ becomes 1, see MP3 codec datasheet, Serial Protocol for SCI | |
while (DREQ == 0) | |
; | |
} | |
// Function reads words_count words from MP3 SCI | |
void MP3_SCI_Read(char start_address, char words_count, unsigned int *data_buffer) { | |
unsigned int temp; | |
MP3_CS = 0; // select MP3 SCI | |
SPI1_Write(READ_CODE); // Enter into reading mode | |
SPI1_Write(start_address); // Start reading from the starting address | |
while (words_count) { // read words_count words byte per byte | |
words_count--; | |
temp = SPI1_Read(0); | |
temp = temp << 8; | |
temp = temp + SPI1_Read(0); | |
*data_buffer = temp; | |
data_buffer++; | |
} | |
MP3_CS = 1; // deselect MP3 SCI | |
// wait until DREQ becomes 1, see MP3 codec datasheet, Serial Protocol for SCI | |
while (DREQ == 0) | |
; | |
} | |
// Function write one byte to MP3 SDI | |
void MP3_SDI_Write(char data_) { | |
MP3_CS = 1; // deselect MP3 SCI | |
BSYNC = 0; | |
// wait until DREQ becomes 1, see MP3 codec datasheet, Serial Protocol for SCI | |
while (DREQ == 0) | |
; | |
SPI1_Write(data_); // write data to MP3 codec | |
BSYNC = 1; | |
} | |
// Function Write 32 bytes to MP3 SDI | |
void MP3_SDI_Write_32(char *data_) { | |
char i; | |
MP3_CS = 1; | |
BSYNC = 0; | |
// wait until DREQ becomes 1, see MP3 codec datasheet, Serial Protocol for SCI | |
while (DREQ == 0) | |
; | |
for (i=0; i<32; i++) | |
SPI1_Write(data_[i]); | |
BSYNC = 1; | |
} | |
// Function set volume on the left and right channel | |
void MP3_Set_Volume(char left, char right) { | |
unsigned int volume; | |
volume = (left<<8) + right; // calculate value | |
MP3_SCI_Write(SCI_VOL_ADDR, volume); // Write value to VOL register | |
} | |
// Function updates volume if volume Buttons are pressed | |
void MP3_Check_Volume() { | |
char old_volume_left, old_volume_right; | |
BtnLeftDown_Direction = 1; // set pin direction as input | |
BtnLeftUp_Direction = 1; | |
BtnRightDown_Direction = 1; | |
BtnRightUp_Direction = 1; | |
BtnLeftDown = 0; // set pin value to zero | |
BtnLeftUp = 0; | |
BtnRightDown = 0; | |
BtnRightUp = 0; | |
old_volume_left = volume_left; // save volume values | |
old_volume_right = volume_right; | |
if (BtnLeftDown) { // RD3 pressed = LEFT VOLUME DOWN command | |
if (volume_left < 255) { | |
volume_left++; | |
} | |
} | |
if (BtnLeftUp) { // RD2 pressed = LEFT VOLUME UP command | |
if (volume_left > 0) { | |
volume_left--; | |
} | |
} | |
if (BtnRightDown) { // RD1 pressed = RIGHT VOLUME DOWN command | |
if (volume_right < 255) { | |
volume_right++; | |
} | |
} | |
if (BtnRightUp) { // RD0 pressed = RIGHT VOLUME UP command | |
if (volume_right > 0) { | |
volume_right--; | |
} | |
} | |
// if volume values are changed, set volume to new values | |
if ( (volume_left != old_volume_left) || (volume_right != old_volume_right) ) { | |
MP3_Set_Volume(volume_left,volume_right); | |
} | |
} | |
// Function initializes MP3 codec | |
void MP3_Init() { | |
MP3_CS_Direction = 0; // Configure MP3_CS as output | |
MP3_CS = 1; // Deselect MP3_CS | |
MP3_RST_Direction = 0; // Configure MP3_RST as output | |
MP3_RST = 1; // Set MP3_RST pin | |
DREQ_Direction = 1; // Configure DREQ as input | |
BSYNC_Direction = 0; // Configure BSYNC as output | |
BSYNC = 0; // Clear BSYNC | |
// Initialize SPI1 module | |
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV16, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH); | |
// Hardware reset | |
MP3_RST = 0; | |
Delay_ms(10); | |
MP3_RST = 1; | |
// wait until DREQ becomes 1, see MP3 codec datasheet, Serial Protocol for SCI | |
while (DREQ == 0) | |
; | |
MP3_SCI_Write(SCI_MODE_ADDR, 0x0800); | |
MP3_SCI_Write(SCI_BASS_ADDR, 0x7A00); | |
MP3_SCI_Write(SCI_CLOCKF_ADDR, 0xC000); // default 12 288 000 Hz + PLL | |
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH); | |
Delay_ms(100); | |
// Maximum volume is 0x00 and total silence is 0xFE. | |
volume_left = 50; // Set volume to initial value | |
volume_right = 50; | |
MP3_Set_Volume(volume_left,volume_right); | |
Delay_ms(1000); | |
} | |
// Function plays mp3 file | |
// Instead of void MP3_Play() we will have | |
void MP3_Play(char filename[]) { | |
unsigned long i; | |
if (Mmc_Fat_Init() == 0) { | |
// I have commented out some of the LCD messages | |
// Lcd_Cmd(_LCD_CLEAR); // Clear display | |
// Lcd_Out(1,5,"MMC FAT"); | |
// Lcd_Out(2,1,"initialized"); | |
// Delay_ms(500); | |
// I have moved these lines to the main code | |
// Lcd_Cmd(_LCD_CLEAR); // Clear display | |
// Lcd_Out(1,1,"Playing file :"); | |
// Lcd_Out(2,1,filename); | |
// The code line | |
// if (Mmc_Fat_Assign("sound.mp3", 0) ) | |
// becomes | |
if (Mmc_Fat_Assign(filename, 0) ) { | |
// the rest of the code remains unchanged | |
// Lcd_Cmd(_LCD_CLEAR); // Clear display | |
///Lcd_Out(1,2,"File Assigned"); | |
Delay_ms(100); // Shorter delay than in the code example | |
Mmc_Fat_Reset(&file_size); // Call Reset before file reading, | |
// procedure returns size of the file | |
// send file blocks to MP3 SDI | |
while (file_size > BUFFER_SIZE) { | |
// Set the SPI faster when reading data from mikro SD memory | |
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH); | |
for (i=0; i<BUFFER_SIZE; i++) { | |
Mmc_Fat_Read(mp3_buffer + i); | |
} | |
// Set the SPI slower when sending data to mp3 codec | |
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV16, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH); | |
for (i=0; i<BUFFER_SIZE/BYTES_2_WRITE; i++) { | |
MP3_SDI_Write_32(mp3_buffer + i*BYTES_2_WRITE); | |
} | |
file_size -= BUFFER_SIZE; | |
MP3_Check_Volume(); // Update volume | |
} | |
// send the rest of the file to MP3 SDI | |
// Set the SPI faster when reading data from mikro SD memory | |
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH); | |
for (i=0; i<file_size; i++) { | |
Mmc_Fat_Read(mp3_buffer + i); | |
} | |
// Set the SPI slower when sending data to mp3 codec | |
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV16, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH); | |
for (i=0; i<file_size; i++) { | |
MP3_SDI_Write(mp3_buffer[i]); | |
} | |
// Display finishing message | |
// Lcd_Cmd(_LCD_CLEAR); // Clear display | |
// Lcd_Out(1,4,"Finished."); | |
Delay_ms(1500); | |
} | |
// Display error message | |
// Those messages remain as I want to know if something goes wrong | |
else { | |
Lcd_Cmd(_LCD_CLEAR); // Clear display | |
Lcd_Out(1,1,"File not"); | |
Lcd_Out(2,4,"assigned"); | |
Delay_ms(1500); | |
} | |
} | |
// Display error message | |
else { | |
Lcd_Cmd(_LCD_CLEAR); // Clear display | |
Lcd_Out(1,5,"MMC FAT"); | |
Lcd_Out(2,1,"not initialized"); | |
Delay_ms(1500); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Module functions | |
void MP3_Init(); | |
// To be able to pass filenames into the MP3 function we have to change | |
// void MP3_Play(); | |
// to | |
void MP3_Play(char filename[]); | |
void MP3_SCI_Write(char address, unsigned int data_in); | |
void MP3_SCI_Read(char start_address, char words_count, unsigned int *data_buffer); | |
void MP3_SDI_Write(char data_); | |
void MP3_SDI_Write_32(char *data_); | |
void MP3_Set_Volume(char left, char right); | |
void MP3_Check_Volume(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Project page | |
# dd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment