用一块淘宝上淘来的空PCB焊接上PIC18F46J11和PL2303,经过调试,让MCU可以给主机发ASCII码串,MCU可以接收主机键盘发出的字符。
硬件电路如下2图。
BACK.jpg (643.26 KB, 下载次数: 0)
下载附件
2012-4-19 15:11 上传
调试中MCU与PL2303之间的串口比较难调,把背板图中连接二者的跳线去掉,让各自的TX/RX短路,形成自环。PC侧可以让自己键盘输入都在自己的屏幕上显示;MCU侧可以运行中断后在串口接收缓冲区看到自己发送的数据。
调试正常的程序如下。其中RTCC部分可以为后续的开发(例如连续输出日期时间)保留。
#include "P18f46j11.h"
#include "usart.h"
#include "delays.h"
#define LED1 LATDbits.LATD2
void main (void);
void InterruptHandlerHigh (void);
unsigned int test1;
unsigned char Rtimehi[4]={0x0,0x03,0x05,0x10},Rtimelo[4]={0x12,0x09,0x0,0x30};
unsigned char usart_data[20]; //usart送来的数据暂存
unsigned char *usart_head; //usart数据暂存区的头指针
unsigned char try_tx1;
//***************主函数*****************
void main()
{
unsigned char i,j;
//*************************RTCC初始化*******************
T1GCON=0;
T1CON=0X3F; //允许tmr1的振荡器
RTCCFG=0X05;
PADCFG1=0X02; //输出秒时钟
ALRMRPT=0XFF; //闹钟重复次数
ALRMCFG=0XC4; //闹钟开,定闹开,指针指向分秒,1“掩码
ALRMVALL=0; //秒内容清除
ALRMVALH=0; //分内容清除
PIE3bits.RTCCIE=1; //开闹钟中断
//以下汇编部分为实时钟写入开启前的必需动作
EECON2=0x55; //修改重定位锁定标志前的必须序列
EECON2=0xAA;
RTCCFGbits.RTCWREN=1; //开启写入
RTCCFGbits.RTCEN=1;
RTCCFG|=0x03; //置指针为0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //写
{
RTCVALL=Rtimelo
;
RTCVALH=Rtimehi;
}
//以下汇编部分为关闭实时钟写入前的必需动作
EECON2=0x55; //修改重定位锁定标志前的必须序列
EECON2=0xAA;
RTCCFGbits.RTCWREN=0; //关闭写入
RTCCFG|=0x03; //置指针为0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //读
{
Rtimelo=RTCVALL;
Rtimehi=RTCVALH;
}
//***************USART1 INIT**********************
Close1USART(); //关闭串口
//下句打开串口1,收中断,高速,4800
Open1USART( USART_TX_INT_OFF &
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_LOW,
103 );
RCSTA1bits.ADDEN=0; //消除9位通信的地址相关设置
BAUDCON1bits.ABDOVF=0; //将波特率计满指示清0
BAUDCON1bits.RXDTP=0; //将空闲反相关闭
BAUDCON1bits.BRG16=1; //选择16位波特率
usart_head=usart_data; //指针到队列头
//****************INTERRUPT INIT*******************
INTCONbits.PEIE=1;
INTCONbits.GIE=1;
//**************************IO INIT********************
TRISDbits.TRISD2=0; //RD2 led output
test1=0;
try_tx1=0x30;
//**************************主循环************************
while(1)
{
Delay1KTCYx(100); //减慢发送速度而设
//以下读RTCC到两个数组中
RTCCFG|=0x03; //置指针为0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //读
{
Rtimelo=RTCVALL;
Rtimehi=RTCVALH;
}
//检查串口空则循环发送ASCII表中的部分码
if (TXSTA1bits.TRMT)
{
TXREG1=try_tx1;
LED1^=1; //测试指示
if (try_tx1>0x76)
try_tx1=0x30;
else
try_tx1++;
}
//到达MAIN最后部分
}
}
//----------------------------------------------------------------------------
// High priority interrupt vector
#pragma code InterruptVectorHigh = 0x08
void
InterruptVectorHigh (void)
{
_asm
goto InterruptHandlerHigh //jump to interrupt routine
_endasm
}
//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerHigh
void InterruptHandlerHigh ()
{
if (PIR1bits.RC1IF)
{
*usart_head = RCREG1; //若USART1收中断,以读出数据方式清除标志
usart_head++; //指针增1,指向下个地址
if (usart_head>=&usart_data[19]) //若到队尾
usart_head=usart_data; //指针回到队列头
}
else if (PIR3bits.RTCCIF)
{
PIR3bits.RTCCIF = 0; //clear interrupt flag
test1++;
}
}
iic_thermal.jpg (584.32 KB, 下载次数: 0)
下载附件
2012-4-24 13:40 上传
以下是带LM75A温度芯片后调通的程序。
#include "P18f46j11.h"
#include "usart.h"
#include "stdlib.h"
#include "i2c.h"
#include "math.h"
#include "delays.h"
#define LED1 LATDbits.LATD2
//以下预先声明各个函数
void iic_start(void);
void iic_rstart(void);
void iic_stop(void);
void iic_write(unsigned char);
unsigned char iic_read(unsigned char);
void main (void);
void InterruptHandlerHigh (void);
unsigned int test1,iic_err=0;
unsigned char Rtimehi[4]={0x0,0x03,0x05,0x10},Rtimelo[4]={0x12,0x09,0x0,0x30};
unsigned char usart_data[20]; //usart送来的数据暂存
unsigned char *usart_head; //usart数据暂存区的头指针
unsigned char usrt_tx[55]="the temperature is: ";
unsigned char *usrt_tx_head=usrt_tx;
unsigned char iic_rd1,iic_rd2;
//***************主函数*****************
void main()
{
unsigned char i,j;
//*************************RTCC初始化*******************
T1GCON=0;
T1CON=0X3F; //允许tmr1的振荡器
RTCCFG=0X05;
PADCFG1=0X02; //输出秒时钟
ALRMRPT=0XFF; //闹钟重复次数
ALRMCFG=0XC4; //闹钟开,定闹开,指针指向分秒,1“掩码
ALRMVALL=0; //秒内容清除
ALRMVALH=0; //分内容清除
PIE3bits.RTCCIE=1; //开闹钟中断
//以下汇编部分为实时钟写入开启前的必需动作
EECON2=0x55; //修改重定位锁定标志前的必须序列
EECON2=0xAA;
RTCCFGbits.RTCWREN=1; //开启写入
RTCCFGbits.RTCEN=1;
RTCCFG|=0x03; //置指针为0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //写
{
RTCVALL=Rtimelo;
RTCVALH=Rtimehi;
}
//以下汇编部分为关闭实时钟写入前的必需动作
EECON2=0x55; //修改重定位锁定标志前的必须序列
EECON2=0xAA;
RTCCFGbits.RTCWREN=0; //关闭写入
RTCCFG|=0x03; //置指针为0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //读
{
Rtimelo=RTCVALL;
Rtimehi=RTCVALH;
}
//***************USART1 INIT**********************
Close1USART(); //关闭串口
//下句打开串口1,收中断,高速,4800
Open1USART( USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE &
USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW,103 );
RCSTA1bits.ADDEN=0; //消除9位通信的地址相关设置
BAUDCON1bits.ABDOVF=0; //将波特率计满指示清0
BAUDCON1bits.RXDTP=0; //将空闲反相关闭
BAUDCON1bits.BRG16=1; //选择16位波特率
usart_head=usart_data; //指针到队列头
usrt_tx[51]=0x0d; //在发送缓冲区末尾放置回车升格标记
usrt_tx[52]=0x0a;
usrt_tx[53]=0;
usrt_tx[54]=0;
usrt_tx[23]=0x2e; //"."
usrt_tx[25]=0x23; //"#"
usrt_tx[26]=0x43; //"C"
usrt_tx[27]=0x0d; //" "
usrt_tx[28]=0x0a; //" "
//****************iic模式初始化****************
TRISCbits.TRISC3=1; //SSP1SCL,IIC模块要求
TRISCbits.TRISC4=1; //SSP1SDA,IIC模块要求
PIE1bits.SSP1IE=0;
ODCON3bits.SPI1OD=1; //spi1集电极开路打开
SSP1STAT=0X80; //100k/1M标准速率模式
SSP1CON1=0X28; //IIC主模式,FOSC/(4 * (SSPxADD + 1))时钟,IIC允许
SSP1CON2=0; //清除所有通信标示
SSP1ADD=79; //8m 100k速率
IPR1bits.SSP1IP=1; //高优先级
//****************INTERRUPT INIT*******************
INTCONbits.PEIE=1;
INTCONbits.GIE=1;
//**************************IO INIT********************
TRISDbits.TRISD2=0; //RD2 led output
test1=0;
//*********写入和读出LM75A*************************
iic_start();
iic_write(0x9E); //ADRRESS OF LM75A, write
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_write(0x01); //pointer OF LM75A
iic_write(0x0); //OS active low
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_stop();
Delay1KTCYx(200); //
iic_start();
iic_write(0x9e); //ADRRESS OF LM75A, write
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_write(0); //pointer OF LM75A, temprature
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_rstart();
iic_write(0x9f); //ADRRESS OF LM75A, read
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_rd1=iic_read(0);
iic_rd2=iic_read(1);
iic_stop();
//**************************主循环************************
while(1)
{
//Sleep();
//以下读RTCC到两个数组中
RTCCFG|=0x03; //置指针为0b11
while (RTCCFGbits.RTCSYNC); //等待不忙
for (i=0;i<4;i++) //读
{
Rtimelo=RTCVALL;
Rtimehi=RTCVALH;
}
Delay1KTCYx(200); //减慢发送速度而设
//以下读出LM75A
iic_start();
iic_write(0x9e); //ADRRESS OF LM75A, write
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_write(0); //pointer OF LM75A, temprature
iic_rstart();
iic_write(0x9f); //ADRRESS OF LM75A, read
if (SSP1CON2bits.ACKSTAT)
iic_err+=1; //如果iic不响应则监测+1
iic_rd1=iic_read(0);
iic_rd2=iic_read(1);
iic_stop();
//put the temp data into tx quere
usrt_tx[21]=(iic_rd1%100)/10+0x30;
usrt_tx[22]=(iic_rd1%100)%10+0x30;
usrt_tx[24]=(iic_rd2>>5)+0x30; //这个换算不准确,仅用来标志小数存在
//检查串口空则发送usrt_tx中的内容
if (TXSTA1bits.TRMT)
{
TXREG1=*usrt_tx_head;
LED1^=1; //测试指示
if ((usrt_tx_head>=&usrt_tx[53])|(*usrt_tx_head==0))
usrt_tx_head=usrt_tx;
else
usrt_tx_head++;
}
//到达MAIN最后部分
}
}
//----------------------------------------------------------------------------
// High priority interrupt vector
#pragma code InterruptVectorHigh = 0x08
void
InterruptVectorHigh (void)
{
_asm
goto InterruptHandlerHigh //jump to interrupt routine
_endasm
}
//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerHigh
void InterruptHandlerHigh ()
{
if (INTCONbits.TMR0IF)
{ //check for TMR0 overflow
INTCONbits.TMR0IF = 0; //clear interrupt flag
}
else if (PIR1bits.RC1IF)
{
*usart_head = RCREG1; //若USART1收中断,以读出数据方式清除标志
usart_head++; //指针增1,指向下个地址
if (usart_head>=&usart_data[19]) //若到队尾
usart_head=usart_data; //指针回到队列头
}
else if (PIR3bits.RTCCIF)
{
PIR3bits.RTCCIF = 0; //clear interrupt flag
test1++;
}
}
/////////////////iic子程序//////////////
void iic_start()
{
SSP1CON2bits.SEN = 1; //SET SEN
while (!PIR1bits.SSP1IF); //WAIT ACK FROM SLAVE
PIR1bits.SSP1IF =0; //CLEAR FLAG
}
void iic_rstart() //再启动
{
SSP1CON2bits.RSEN = 1; //SET RSEN
while (!PIR1bits.SSP1IF); //WAIT ACK FROM SLAVE
PIR1bits.SSP1IF =0; //CLEAR FLAG
}
void iic_stop()
{
SSP1CON2bits.PEN = 1; //SET PEN
while (!PIR1bits.SSP1IF); //WAIT ACK FROM SLAVE
PIR1bits.SSP1IF =0; //CLEAR FLAG
}
void iic_write(unsigned char thebyte)
{
SSP1BUF = thebyte; //put in the byte
while (!PIR1bits.SSP1IF); //WAIT ACK FROM SLAVE
PIR1bits.SSP1IF =0; //CLEAR FLAG
}
unsigned char iic_read(unsigned char NotACK)
{
unsigned char gotiicbyte;
SSP1CON2bits.ACKDT=NotACK; //字节接收结束后,该位为0则继续接收,为1则停止接收
SSP1CON2bits.RCEN = 1; //SET RCEN
while (SSP1CON2bits.RCEN); //WAIT receiving ends
SSP1CON2bits.ACKEN=1;
while (SSP1CON2bits.ACKEN); //WAIT SLAVE GOT THE ACK/NACK FLAG
gotiicbyte=SSP1BUF; //读到的内容
return gotiicbyte;
}
下图为运行效果。
当然是现成的USB/TTL转换芯片。问题是,你转换之后怎样让你的应用在PC与mcu平台上实现你自己需要内容的显示和会话?我这个就是实现了这些功能的案例。
串口连通仅仅是开始。要做的工作是物理连通之后应用的开发。
PS:我前面贴出的程序确实是较早版本。在这个版本基础上,后面又写了PC键盘修改日期时间的部分,还有连接另外一个串口的汉语语音合成芯片通信的部分。现在该平台的两个MSSP和两个USART都用起来了。程序略长,不贴了。带PC修改日期时间功能的程序贴在别的站了。
一周热门 更多>