Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC 18F2550 and MT8888 DTMF Transceiver

Status
Not open for further replies.

dbachman

New Member
Does anyone have any experience with interfacing an MT8888 DTMF transceiver to a PIC controller? Basically I have been having fits trying to get the timing correct to output a tone. Any help at all would be appreciated.

Thanks, Don: :(
 
I need to be able to send the 4 bit code representing a number and have the MT8888 produce the tone . Also, I would need to decode the incoming tone to the MT8888 and send the 4 bit code to the PIc.

Thanks, Don
 
This is how it is wired and here is some code I have tried.

Code:
OSCCON = $60 ' Set up internal oscillator


x var byte
dtmf var byte

CS var portb.4 'Enable or disable MT8888
RD var portb.5 'Read Microprocessor input
WR var portb.6 'Write Microprocessor input
RS var portb.7 'Register Select

data @1,8,7,0,7,3,7,5
TRISB = %00000000
portb = %11000000
portb = %10100000
portb = %10100000
portb = %10101000
portb = %10100000
portb = %11000000 
pause 10
Send_DTMF:
portb = %10101101 'Send Control Register A
portb = %10100000 'Send Control Register B

portb = %10100110 'Send digit = 7
 
portb = %10100100 '    Send digit = 5



Goto Send_DTMF
 

Attachments

  • Pic.jpg
    Pic.jpg
    21.2 KB · Views: 1,042
This is how it is wired and here is some code I have tried.
Code:
Send_DTMF:
portb = %10101101 'Send Control Register A
portb = %10100000 'Send Control Register B
portb = %10100110 'Send digit = 7
portb = %10100100 '    Send digit = 5
I'm not familiar with PIC basic but:
You need to setup the D0-D3, RSO and CS pins first while maintaining WR and RD high. Then you wait a minimum of 45ns. Then you toggle WR low for a minimum of 150ns and then high again to write data to the MT8888. Then you wait a minimum of 100ns. Then you can repeat with the next command. You are trying to do all this with one 8bit write to portB which isn't the same and won't work. You'll also have to read the STATUS register in the MT8888 to see if it is ready to accept new data. ie: You must give time for the DTMF tone to be played before you command it to send the next one.
 
Last edited:
You need to setup the D0-D3, RSO and CS pins first while maintaining WR and RD high.

What do I do with RS0? I thought it was just used in conjunction with RD and WR to set up the control registers A and B.

Do I set CS low to enable the MT8888? and leave it low?

I am looking at the datasheet 'Typical control sequence for burst mode applications' and I don't see CS in there at all however, it is used in the write timing diagram. I guess I just need to know how you would set up the above quote in a statement or two.

Thanks for jumping in, Don
 
What do I do with RS0? I thought it was just used in conjunction with RD and WR to set up the control registers A and B.
When setting up the control registers or read the status register, you set RS0 high.
When sending or receiving a DTMF digit, you set RS0 low.
Do I set CS low to enable the MT8888? and leave it low?
Yes, you could tie it low to ground permanently in this application. It is typically used when interfacing the MT8888 to a microprocessor's data buss where there are multiple devices on the same buss. When it is high, D0-D3, RSO, WR & RD have no effect.
Thanks for jumping in, Don
No problem.
 
I am going to try this, how do you think it looks?

Code:
OSCCON = $60 ' Set up internal oscillator

CS var portb.4 'Enable or disable MT8888 tied to ground
RD var portb.5 'Read Microprocessor input
WR var portb.6 'Write Microprocessor input
RS var portb.7 'Register Select

TRISB = %00000000 'Set portb to output
portb = %11000000
portb = %10100000
portb = %10100000
portb = %10101000
portb = %10100000
portb = %11000000 
pause 10

Send_DTMF:
portb = %10101101 'Set up Control Register A
pause 1 'Wait 1 millisecond
portb = %10100000 'Set up Control Register B
pause 1 'Wait 1 millisecond
portb = %01100000 'Set WR, RD high CS and RS0 and rest of portb low
pause 1 'Wait 1 millisecond
portb = %00000110 'Send digit = 6
pause 10 'wait 10 milliseconds
low WR   'Take portb pin 6 low
pause 10 'wait 10 milliseconds
high WR   'take portb pin 6 high

Goto Send_DTMF 'loop forever
 
End

I am not sure about the MT8888 initialization (datasheet page 4-101) do I need this?
It says to do this 100ms after power up.

portb = %11000000
portb = %10100000
portb = %10100000
portb = %10101000
portb = %10100000
portb = %11000000

Thanks again, Don
 

Attachments

  • PIC-ENC-DEC1.JPG
    PIC-ENC-DEC1.JPG
    50.9 KB · Views: 963
Last edited:
I am going to try this, how do you think it looks?
It's not going to work. I suggest that you create a subroutine for writing commands to the MT8888. Syntax will be wrong, but this is the idea:

Code:
sub WriteControlRegister(command)
   command = command AND 0x0F 'Mask off upper 4 bits with Logical AND
   portb = command OR %11100000 'Set upper 3 bits with Logical OR and send to portb
   pause 1 'Wait 1 millisecond (may not be needed)
   low WR   'Take portb pin 6 low
   pause 1 'Wait 1 millisecond (may not be needed)
   high WR   'take portb pin 6 high
end sub
Then all you need to do is:
Code:
WriteControlRegister(%1101) 'Write to Control Register A (tone out, DTMF, IRQ, Select Control Register B)
WriteControlRegister(%0000) 'Write to Control Register B (burst mode)
You should also write a routine to read the status register, read the Rx data register, and write the Tx data register as these will be common tasks which you'll do a lot.
 
Hi KChriste,

I think I can figure out how to make and call a subroutine once I get to the point of getting the MT8888 to reliably produce a tone. Unless, you think subroutines would be the best way from the outset. I was just trying to get the thing to produce a tone and then structure the program to read from a data statement.

Is this:
command = command AND 0x0F 'Mask off upper 4 bits with Logical AND
portb = command OR %11100000 'Set upper 3 bits with Logical OR and send to portb

The same as this:

portb = %10101101

or

portb = %10100000

Depending on which one of these is called

WriteControlRegister(%1101) 'Write to Control Register A (tone out, DTMF, IRQ, Select Control Register B)
WriteControlRegister(%0000) 'Write to Control Register B (burst mode)

What is the reason I can't just write - portb = %10101101?

Here is maybe a start:

Code:
OSCCON = $60 ' Set up internal oscillator

CS var portb.4 'Enable or disable MT8888 tied to ground
RD var portb.5 'Read Microprocessor input
WR var portb.6 'Write Microprocessor input
RS var portb.7 'Register Select

TRISB = %00000000 'Set portb to output
command var byte
data @4,%1101,%0000'Data starting at position #4
data @6,8,7,0,7,3,7,5

WriteControlRegister:
       command = command & $0F 'Mask off upper 4 bits with Logical AND
       portb = command | %11100000 'Set upper 3 bits with Logical OR and send to portb
       pause 1 'Wait 1 millisecond (may not be needed)
       low WR   'Take portb pin 6 low
       pause 1 'Wait 1 millisecond (may not be needed)
       high WR   'take portb pin 6 high
Return

WritetransmitRegister:
       command = command & $0F 'Mask off upper 4 bits with Logical AND
       portb = command | %11100000 'Set upper 3 bits with Logical OR and send to portb
       pause 1 'Wait 1 millisecond (may not be needed)
       low WR   'Take portb pin 6 low
       pause 1 'Wait 1 millisecond (may not be needed)
       high WR   'take portb pin 6 high
 return
       
SetupAandB:
for x = 4 to 5
read x, command 'Read data statement starting at location #4 and put in command
gosub writecontrolregister
next x
gosub Setuptransmitregister



Setuptransmitregister:
for x = 6 to 12
read x, command 'Read data statement starting at location #6 and put in command
gosub writetransmitregister
next x

End

Thanks, Don
 
Last edited:
Unless, you think subroutines would be the best way from the outset.
I highly recommend that you do so. It will make writing our code much easier to understand and you will be less prone to making mistakes. Once the SUBs are written, you'll no longer have to think about the hardware interface with the MT8888 much. ie: you won't have to remember to toggle WR every time you write a nibble to the MT8888.
What is the reason I can't just write - portb = %10101101?
Because this:
Code:
WriteControlRegister(%[COLOR="Red"]1101[/COLOR]) 'Write to Control Register A (tone out, DTMF, IRQ, Select Control Register B)
WriteControlRegister(%[COLOR="Blue"]0000[/COLOR]) 'Write to Control Register B (burst mode)
Is equal to this:

Code:
   portb = %1110[COLOR="Red"]1101[/COLOR]
   pause 1 'Wait 1 millisecond (may not be needed)
   portb = %1010[COLOR="Red"]1101[/COLOR]  'Take portb bit 6 low
   pause 1 'Wait 1 millisecond (may not be needed)
   portb = %1110[COLOR="Red"]1101[/COLOR]  'take portb bit 6 high
  ' Small delay here due to routine above returning

  ' and the routine below being called.
   portb = %1110[COLOR="Blue"]0000[/COLOR]
   pause 1 'Wait 1 millisecond (may not be needed)
   portb = %1010[COLOR="Blue"]0000[/COLOR]  'Take portb bit 6 low
   pause 1 'Wait 1 millisecond (may not be needed)
   portb = %1110[COLOR="Blue"]0000[/COLOR]  'take portb bit 6 high
As you can see, using SUBs will make your code easier to maintain, understand and take up less code space.
 
I am having a bit of trouble with the MT8888 as it wants to oscilliate and produce a tone even while it is diconnected from power. Sounds kind of strange but it is still hooked up to the pic. I have completely erased the pic and disconnected it from the MT8888 but when I connect it back up it produces a tone. Before I couldn't get it to make a peep and now it wont shut up. Maybe the cheap solderless board I'm using.

Don
 
Remember that the MT8888 is a CMOS device and has built in protection diodes on the inputs which connect to Vdd and Vss. If one or more of the inputs is held high, then the MT8888 will be powered via the protection diode on the input pin.
It could also be a breadboard problem.
 
Hi Kchriste,

I don't want to seem like I am slacking on writing this code, but I haven't gotten very far with what I have done. I was wondering if you could show me a snippet that produces a tone just to make sure everything I have wired is working ok. I ordered a few more MT8888's just in case I fried this one.

Thanks Don
 
Hi Kchriste,

I am waiting for a shipment of 6 new MT8888's before I continue. I have tried a bit to get this one to work but I think I may have fried it.

Don
 
Pic18F2550 and MT8888 problems

Hi KChriste, Are you still around?

I was wondering if you or someone could look at this code and see where I am going wrong. I realize you aren't PicBasic savvy but it is kind of straight forward. It still doesn't seem to work.

Thanks, Don

Code:
OSCCON = $60 							'Set up internal oscillator

CS var portb.4 							'Enable or disable MT8888 tied to ground
RD var portb.5 							'Read Microprocessor input
WR var portb.6 							'Write Microprocessor input
RS var portb.7 							'Register Select

TRISB = %00000000						'Set portb to output

Init var byte 						
Control var byte
Dtmf var byte
Status var byte
w var byte
X var byte
y var byte
z var byte

data @1,%11000000,%10100000,%10101000,%10100000,%10101101,%10100000,%00001000,%00001110,%00000001,%00001110,%00000011,%00001110,%00000110 'Data starting at position #1

Gosub Initialization
gosub SetupControlRegister
gosub WriteTransmitRegister

Initialization:
		Gosub ReadStatusRegister
		for w = 2 to 4
		read w, Init 				  'Read data statement starting at location #2 and put in Init
		Init = Init & $0F			  'Mask off upper 4 bits with Logical AND
		portb = Init | %11100000   		  'Set upper 3 bits with Logical OR and send to portb
		pause 10 				  'Wait 1 millisecond (may not be needed)
       		low WR   				  'Take portb pin 6 low
       		pause 10 				  'Wait 1 millisecond (may not be needed)
      		high WR                        		  'take portb pin 6 high
      		pause 10
		Next w
		
Return

ReadstatusRegister:
		
		read 1, Status 				 'Read data statement starting at location #1 and put in Status   
		Status = Status & $0F			 'Mask off upper 4 bits with Logical AND
		portb = Status | %11100000 	 	 'Set upper 3 bits with Logical OR and send to portb
		pause 10 				 'Wait 1 millisecond (may not be needed)
       		low RD   			         'Take portb pin 5 low
       		pause 10 				 'Wait 1 millisecond (may not be needed)
      		high RD   				 'take portb pin 5 high
      		pause 10
Return


SetupControlRegister:
		
		for x = 5 to 6
		read x, Control 			 'Read data statement starting at location #6 and put in Control
		Control = Control & $0F		 	 'Mask off upper 4 bits with Logical AND
		portb = Control | %11100000  		 'Set upper 3 bits with Logical OR and send to portb
		pause 10 				 'Wait 1 millisecond (may not be needed)
       		low WR   				 'Take portb pin 6 low
       		pause 10 				 'Wait 1 millisecond (may not be needed)
      		high WR   				 'take portb pin 6 high
      		pause 10
		Next X
Return


WriteTransmitRegister:
		
		for y = 7 to 13               
		read y, Dtmf 				 'Read data statement starting at location #9 and put in Dtmf
		Dtmf = Dtmf & $0F			 'Mask off upper 4 bits with Logical AND
		portb = Dtmf | %11100000 	         'Set upper 3 bits with Logical OR and send to portb
		pause 10 				 'Wait 1 millisecond (may not be needed)
       		high RD   				 'Take portb pin 5 high
       		pause 10 				 'Wait 1 millisecond (may not be needed)
      		low RD     				 'take portb pin 5 low
      		pause 10
		Next y

Return


End
 
Last edited:
In your Initialization routine, you only do 3 writes to the control registers. The Data sheet shows 4 writes with the first two being duplicated. Since the upper 4bits are masked off anyway, you could fix that by changing for w = 2 to 4 to for w = 1 to 4
There is also supposed to be a read from the status register at the beginning of the Initialization routine and at the end. You only have it at the beginning.
I have only glanced briefly at the rest of the code.
 
Last edited:
The Apps engineer a Zarlink said the Write was a redundant one. Have a look at this code using an MT8880 (which is almost the same). It's datasheet is very similar. It doesn't even initialize it even tho the datasheet says it should. Also this attachment. I am not good at Assembly.

Thanks, Don

Code:
' Listing 1. Stamp-Based Autodialer
' Program: DIAL.SRC (Sends a string of DTMF tones via the 8880)
' This program demonstrates how to use the CM8880 as a DTMF tone
' generator. All that's required is to initialize the 8880 properly,
' then write the number of the desired DTMF tone to the 8880's
' 4-bit bus.
' The symbols below are the pin numbers to which the 8880's
' control inputs are connected, and one variable used to read
' digits out of a lookup table.
SYMBOL RS_p = 4 ' Register-select pin (0=data).
SYMBOL RW_p = 5 ' Read/Write pin (0=write).
SYMBOL CS_p = 6 ' Chip-select pin (0=active).
SYMBOL digit = b2 ' Index of digits to dial.
' This code initializes the 8880 for dialing by writing to its
' internal control registers CRA and CRB. The write occurs when
' CS (pin 6) is taken low, then returned high. See the accompanying
' article for an explanation of the 8880's registers.
let pins = 255 ' All pins high to deselect 8880.
let dirs = 255 ' Set up to write to 8880 (all outputs).
let pins = %00011011 ' Set up register A, next write to register B.
high CS_p
let pins = %00010000 ' Clear register B; ready to send DTMF.
high CS_p
Stamp Applications no. 7, September 1995
7
' This for/next loop dials the seven digits of my fax number. For
' simplicity, it writes the digit to be dialed directly to the output
' pins. Since valid digits are between 0 and 15, this also takes RS,
' RW, and CS low--perfect for writing data to the 8880. To complete
' the write, the CS line is returned high. The initialization above
' sets the 8880 for tone bursts of 200 ms duration, so we pause
' 250 ms between digits. Note: in the DTMF code as used by the phone
' system, zero is represented by ten (1010 binary) not 0. That's why
' the phone number 459-0623 is coded 4,5,9,10,6,2,3.
for digit = 0 to 6
lookup digit,(4,5,9,10,6,2,3),pins ' Write current digit to pins.
high CS_p ' Done with write.
pause 250 ' Wait to dial next digit.
next digit
end
' Listing 2.
 

Attachments

  • CM8880Transceiver.pdf
    743.7 KB · Views: 1,750
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top