一个经PL2303转换的串口调试实例

2020-02-08 09:13发布

用一块淘宝上淘来的空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++;
}
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
7条回答
surf_131
1楼-- · 2020-02-08 13:46
添加一个温度传感器,注意板子迄今只有一处需要切断铜箔,就是R18的R。

iic_thermal.jpg (584.32 KB, 下载次数: 0)

下载附件

2012-4-24 13:40 上传

surf_131
2楼-- · 2020-02-08 17:43
surf_131 发表于 2012-4-24 13:41
添加一个温度传感器,注意板子迄今只有一处需要切断铜箔,就是R18的R。

以下是带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;
}
surf_131
3楼-- · 2020-02-08 21:24
程序写完了。RTCC与温度同时显示,调整RTCC都正常跑。
下图为运行效果。
surf_131
4楼-- · 2020-02-09 01:42
近日连接一块24LC512, 通了. 还要创立"文件系统", 才会实用.
cooleaf
5楼-- · 2020-02-09 06:24
 精彩回答 2  元偷偷看……
surf_131
6楼-- · 2020-02-09 06:36
本帖最后由 surf_131 于 2012-5-10 12:05 编辑
cooleaf 发表于 2012-5-9 13:46
用现成的USB转TTL的模块或组件即可,个人不建议把时间花在这些方面了,除非产品需要这样的接口。就是USB模 ...


当然是现成的USB/TTL转换芯片。问题是,你转换之后怎样让你的应用在PC与mcu平台上实现你自己需要内容的显示和会话?我这个就是实现了这些功能的案例。
串口连通仅仅是开始。要做的工作是物理连通之后应用的开发。

PS:我前面贴出的程序确实是较早版本。在这个版本基础上,后面又写了PC键盘修改日期时间的部分,还有连接另外一个串口的汉语语音合成芯片通信的部分。现在该平台的两个MSSP和两个USART都用起来了。程序略长,不贴了。带PC修改日期时间功能的程序贴在别的站了。

一周热门 更多>