CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

DFPlayer using PIC16F887

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ThanhDan



Joined: 07 Jun 2022
Posts: 19

View user's profile Send private message

DFPlayer using PIC16F887
PostPosted: Mon Jun 13, 2022 5:35 am     Reply with quote

Hi, I'm using PIC16F887 to play music with DFplayer, I could make the DFplayer play short mp3 of length 5 seconds or so by setting delay_ms(5000) but for a full song I would have to, theoretically, set the delay time to match its length... which is not working too well for me. I have to wait exactly the amount of delay time I set before the DFplayer starts and it doesn't even deliver a full song. Here's my code, please give me guidance.
Code:

#include <16f887.h>
#use delay(clock = 8000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,DISABLE_INTS)
#fuses INTRC_IO,NOWDT,NOMCLR,PROTECT,PUT,NOCPD,NOWRT,NOCPD,NOIESO,NOFCMEN,NOBROWNOUT

unsigned int8 send_buf[10];

void send_data(unsigned int8 cmd, unsigned int8 feedback, unsigned int16 data);
void init();


void main(){ 
   init();
   send_data(0x06,0,6);
   while(true)
   {
      send_data(0x08,0,1);
      delay_ms(5000);
   }
}
void init(){
   setup_oscillator(OSC_8MHZ);
}

void send_data(unsigned int8 cmd, unsigned int8 feedback, unsigned int16 data){
   unsigned int8 i;
   unsigned int16 n;
   send_buf[0] = 0x7E;
   send_buf[1] = 0xFF;
   send_buf[2] = 0x06;
   send_buf[3] = cmd;
   send_buf[4] = feedback;
   send_buf[5] = (unsigned int8)(data >> 8);
   send_buf[6] = (unsigned int8)(data);
   n = 0;
   for(i = 1; i <= 6; i ++){
      n += send_buf[i];
   };
   n = - n;
   send_buf[7] = (unsigned int8)(n >> 8);
   send_buf[8] = (unsigned int8)(n);
   send_buf[9] = 0xEF;
   for(i = 0; i < 10; i ++){
      printf("%c",send_buf[i]);
   };
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 6:01 am     Reply with quote

Don't pause.
Poll the unit.
There is an output pin 'Busy', that tells you when the unit is busy!. Wire
this to your PIC, and wait for this to go off.
It goes low when the unit is playing. By far the easiest way.

You can do it in software. The read_status command could be sent every
1/10th second (say), and the value this returns changes when the track
has finished.

Quote:

Returned Data Status
7E FF 06 42 00 01 01 xx xx EF - A track in USB flash drive is being played
7E FF 06 42 00 02 02 xx xx EF - A track in SD card is paused playing
7E FF 06 42 00 01 00 xx xx EF - A track in USB flash drive is stopped playing
7E FF 06 42 00 10 00 xx xx EF - Module in sleep


Busy is easier.

Is this a DFPlayer, or the 'mini'?.
I know the mini automatically sends:

7E FF 06 3C 00 00 yy xx xx EF, where 'yy' is the track number, when it
finishes playing the track, so this can be used to know when this happens.

The data sheet says:
Quote:

3.3.2 .Returned Data of Track Finished Playing
U-Disk finish playback 1st track 7E FF 06 3C 00 00 01 xx xx EF
U-Disk finish playback 2nd track 7E FF 06 3C 00 00 02 xx xx EF
TF card finish playback 1st track 7E FF 06 3D 00 00 01 xx xx EF
TF card finish playback 2nd track 7E FF 06 3D 00 00 02 xx xx EF
Flash finish playback 1st track 7E FF 06 3E 00 00 01 xx xx EF
Flash finish playback 2nd track 7E FF 06 3E 00 00 02 xx xx EF


So I think both units do this. They say you should wait 100mSec after
this is received before asking it to play another track.
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 7:35 am     Reply with quote

quick look..
Add 'ERRORS' to the USE RS232 'options'....
Delete 'Protect' to the fuses...
Add comments at end of lines of code. costs nothing, helps in debugging, like the line n= - n; , which looks really 'weird' to me......
ThanhDan



Joined: 07 Jun 2022
Posts: 19

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 10:59 am     Reply with quote

Ttelmah wrote:
Don't pause.
Poll the unit.
There is an output pin 'Busy', that tells you when the unit is busy!. Wire
this to your PIC, and wait for this to go off.
It goes low when the unit is playing. By far the easiest way.

You can do it in software. The read_status command could be sent every
1/10th second (say), and the value this returns changes when the track
has finished.

Quote:

Returned Data Status
7E FF 06 42 00 01 01 xx xx EF - A track in USB flash drive is being played
7E FF 06 42 00 02 02 xx xx EF - A track in SD card is paused playing
7E FF 06 42 00 01 00 xx xx EF - A track in USB flash drive is stopped playing
7E FF 06 42 00 10 00 xx xx EF - Module in sleep


Busy is easier.

Is this a DFPlayer, or the 'mini'?.
I know the mini automatically sends:

7E FF 06 3C 00 00 yy xx xx EF, where 'yy' is the track number, when it
finishes playing the track, so this can be used to know when this happens.

The data sheet says:
Quote:

3.3.2 .Returned Data of Track Finished Playing
U-Disk finish playback 1st track 7E FF 06 3C 00 00 01 xx xx EF
U-Disk finish playback 2nd track 7E FF 06 3C 00 00 02 xx xx EF
TF card finish playback 1st track 7E FF 06 3D 00 00 01 xx xx EF
TF card finish playback 2nd track 7E FF 06 3D 00 00 02 xx xx EF
Flash finish playback 1st track 7E FF 06 3E 00 00 01 xx xx EF
Flash finish playback 2nd track 7E FF 06 3E 00 00 02 xx xx EF


So I think both units do this. They say you should wait 100mSec after
this is received before asking it to play another track.


Yeah I am using the mini, but for my application, I only need it to play 1 song, as simple as that. How is using the "busy pin" going to help if it sends only information on when the track has already finished playing. I get how it helps with the transition between songs but I only need to play one.
I think my problem lies in void send_data
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 11:16 am     Reply with quote

It can't take another command, till it has finished the one that is playing
So just wait for the line to go high, before you next call the send_data
command.
ThanhDan



Joined: 07 Jun 2022
Posts: 19

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 11:47 am     Reply with quote

Ttelmah wrote:
It can't take another command, till it has finished the one that is playing
So just wait for the line to go high, before you next call the send_data
command.


Thanks for your rapid response, Yes I understand that "the line" (pin 16/ busy pin) going high means that the DFplayer is free, it has finished playing the previous track but my DFplayer doesn't even play anything and the busy pin never went low. This is my revised code, I checked with the pdf to build this code, please have a look, it's quite simple.
Code:

#include <16f887.h>
#use delay(clock = 8000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,DISABLE_INTS)
#fuses INTRC_IO,NOWDT,NOMCLR,PUT,NOCPD,NOWRT,NOCPD,NOIESO,NOFCMEN,NOBROWNOUT

unsigned int8 send_buf[10];

void send_data(unsigned int8 cmd, unsigned int8 feedback);
void volume(unsigned int8 cmd, unsigned int8 feedback);
void init();

void main(){ 
   init();
   volume(0x06,0);
   delay_ms(5000);
   send_data(0x03,0);
   delay_ms(5000);
}
void init(){
   setup_oscillator(OSC_8MHZ);
}

void volume(unsigned int8 cmd, unsigned int8 feedback){
   unsigned int8 i;
   send_buf[0] = 0x7E;           // Start byte
   send_buf[1] = 0xFF;           // Version
   send_buf[2] = 0x06;           // Len
   send_buf[3] = cmd;            // Command, see 3.2
   send_buf[4] = feedback;       // Feedback, always 0 => 0
   send_buf[5] = 0x00;           // High byte (DH), para 1
   send_buf[6] = 0x0F;           // Low byte (DL), para 2
   send_buf[7] = 0xFF;           // checksum highbyte
   send_buf[8] = 0xD5;           // checksum low byte
   send_buf[9] = 0xEF;           // end
   for(i = 0; i < 10; i ++){
      printf("%c",send_buf[i]);
   };
}

void send_data(unsigned int8 cmd, unsigned int8 feedback){
   unsigned int8 i;
   send_buf[0] = 0x7E;           // Start byte
   send_buf[1] = 0xFF;           // Version
   send_buf[2] = 0x06;           // Len
   send_buf[3] = cmd;            // Command, see 3.2
   send_buf[4] = feedback;       // Feedback, always 0 => 0
   send_buf[5] = 0x00;           // High byte (DH), para 1
   send_buf[6] = 0x01;           // Low byte (DL), para 2
   send_buf[7] = 0xFF;           // checksum highbyte
   send_buf[8] = 0xE6;           // checksum low byte
   send_buf[9] = 0xEF;           // end
   for(i = 0; i < 10; i ++){
      printf("%c",send_buf[i]);
   };
}

ThanhDan



Joined: 07 Jun 2022
Posts: 19

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 11:51 am     Reply with quote

Ttelmah wrote:
It can't take another command, till it has finished the one that is playing
So just wait for the line to go high, before you next call the send_data
command.


Hi, thanks for your rapid response. Yes, I understand that the line (busy pin, pin 16) goes high when Dfplayer has finished playing the current song and only then can I send_data to play a new song and there should be a 100ms interval between the events but my Dfplayer doesn't even play anything and the busy pin never went low. Here's my revised code I built using the DF mini pdf, please have a look, it's quite simple
Code:

#include <16f887.h>
#use delay(clock = 8000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,DISABLE_INTS)
#fuses INTRC_IO,NOWDT,NOMCLR,PUT,NOCPD,NOWRT,NOCPD,NOIESO,NOFCMEN,NOBROWNOUT

unsigned int8 send_buf[10];

void send_data(unsigned int8 cmd, unsigned int8 feedback);
void volume(unsigned int8 cmd, unsigned int8 feedback);
void init();

void main(){ 
   init();
   volume(0x06,0);
   delay_ms(5000);
   send_data(0x03,0);
   delay_ms(5000);
}
void init(){
   setup_oscillator(OSC_8MHZ);
}

void volume(unsigned int8 cmd, unsigned int8 feedback){
   unsigned int8 i;
   send_buf[0] = 0x7E;           // Start byte
   send_buf[1] = 0xFF;           // Version
   send_buf[2] = 0x06;           // Len
   send_buf[3] = cmd;            // Command, see 3.2
   send_buf[4] = feedback;       // Feedback, always 0 => 0
   send_buf[5] = 0x00;           // High byte (DH), para 1
   send_buf[6] = 0x0F;           // Low byte (DL), para 2
   send_buf[7] = 0xFF;           // checksum highbyte
   send_buf[8] = 0xD5;           // checksum low byte
   send_buf[9] = 0xEF;           // end
   for(i = 0; i < 10; i ++){
      printf("%c",send_buf[i]);
   };
}

void send_data(unsigned int8 cmd, unsigned int8 feedback){
   unsigned int8 i;
   send_buf[0] = 0x7E;           // Start byte
   send_buf[1] = 0xFF;           // Version
   send_buf[2] = 0x06;           // Len
   send_buf[3] = cmd;            // Command, see 3.2
   send_buf[4] = feedback;       // Feedback, always 0 => 0
   send_buf[5] = 0x00;           // High byte (DH), para 1
   send_buf[6] = 0x01;           // Low byte (DL), para 2
   send_buf[7] = 0xFF;           // checksum highbyte
   send_buf[8] = 0xE6;           // checksum low byte
   send_buf[9] = 0xEF;           // end
   for(i = 0; i < 10; i ++){
      printf("%c",send_buf[i]);
   };
}
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jun 13, 2022 11:57 am     Reply with quote

haven't read the MP3 datasheet but...maybe it doesn't like your 'checksums', and refuses to play ??
ThanhDan



Joined: 07 Jun 2022
Posts: 19

View user's profile Send private message

PostPosted: Tue Jun 14, 2022 12:19 am     Reply with quote

temtronic wrote:
haven't read the MP3 datasheet but...maybe it doesn't like your 'checksums', and refuses to play ??


Yeah it's written in the pdf how to find all other bytes and their meanings except for the checksums, I mean what are those?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 14, 2022 1:22 am     Reply with quote

The checksum formula is at the bottom of page 4 in the datasheet:
http://www.robotsforfun.com/datasheets/DFPlayer.pdf
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Jun 14, 2022 4:46 am     Reply with quote

Thanks to PCM P, I read, well quickly, the datasheet.
Interesting that the device doesn't NEED the checksum !
You have 2 options.
1) use the checksum, so you have to calculate it and send 2 extra bytes.

2) do not use it. Saves calculation and sending the 2 bytes.

For now, try #2. It's easier, cleaner, faster. If it work 100 times out of 100, keep using it.

'Checksums' are a method to confirm that the data sent between devices is correct. Simple ones, like this are easy to code but can fail,depending on the data,rare though.
As stated in the manual, if using an RC 'clock' it's best to use the checksum option. However in your case the devices are next to each other and speed is slow, so I don't think you'll have problems.
ThanhDan



Joined: 07 Jun 2022
Posts: 19

View user's profile Send private message

PostPosted: Tue Jun 14, 2022 9:34 am     Reply with quote

Hi, thank you all so much for helping, I succeeded, turns out I had the file name wrong (I put 001.mp3 when it should have been 0001.mp3), thanks to PCM P datasheet and temtronic's suggestion, I fixed the bugs. I checked with Proteus' virtual terminal to make sure that the UART message being sent is correct and it was so there was only one thing to fix Smile)

You guys are pros way out of my league and probably won't need this but here's the code
Code:

#include <16f887.h>
#use delay(clock = 8000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,DISABLE_INTS)
#fuses INTRC_IO,NOWDT,NOMCLR,PUT,NOCPD,NOWRT,NOCPD,NOIESO,NOFCMEN,NOBROWNOUT

unsigned int8 send_buf[8];

void play_1(unsigned int8 cmd, unsigned int8 feedback);
void volume_max(unsigned int8 cmd, unsigned int8 feedback);
void init();

void main(){ 
   init();
   volume_max(0x06,0);
   delay_ms(5000);
   play_1(0x03,0);
   
}
void init(){
   setup_oscillator(OSC_8MHZ);
}

void volume_max(unsigned int8 cmd, unsigned int8 feedback){
   unsigned int8 i;
   send_buf[0] = 0x7E;           // Start byte
   send_buf[1] = 0xFF;           // Version
   send_buf[2] = 0x06;           // Len
   send_buf[3] = cmd;            // Command, see 3.2
   send_buf[4] = feedback;       // Feedback, always 0 => 0
   send_buf[5] = 0x00;           // High byte (DH), para 1
   send_buf[6] = 0x1E;           // Low byte (DL), para 2
//!   send_buf[7] = 0xFF;           // checksum highbyte
//!   send_buf[8] = 0xD5;           // checksum low byte
   send_buf[7] = 0xEF;           // end
   for(i = 0; i < 8; i ++){
      printf("%c",send_buf[i]);
   };
}

void play_1(unsigned int8 cmd, unsigned int8 feedback){
   unsigned int8 i;
   send_buf[0] = 0x7E;           // Start byte
   send_buf[1] = 0xFF;           // Version
   send_buf[2] = 0x06;           // Len
   send_buf[3] = cmd;            // Command, see 3.2
   send_buf[4] = feedback;       // Feedback, always 0 => 0
   send_buf[5] = 0x00;           // High byte (DH), para 1
   send_buf[6] = 0x01;           // Low byte (DL), para 2
//!   send_buf[7] = 0xFF;           // checksum highbyte
//!   send_buf[8] = 0xE6;           // checksum low byte
   send_buf[7] = 0xEF;           // end
   for(i = 0; i < 8; i ++){
      printf("%c",send_buf[i]);
   };
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group