异步串口UART程序没看明白,希望大家点拨下
在做异步串口UART实验,对厂家提供的例程没看明白,例程中没有任何注释,想了几天都没想明白,代码和原理是如何对应的?例程/*********************************************************************
** Module Name: UART **
** Author: CTH **
** Version: 1.0 **
** CreateDate: 2008-8-10 **
** Description: **
** Remark: **
** Revision History:2008-8-10 **
**Web: http://www.study-kit.com **
**********************************************************************/
/*********************************************************************
** start:2014-3-15 pm 2:00 ******************
** end:2014-3- ******************
*********************************************************************/
#include <csl.h>
#include <csl_pll.h>
#include <csl_emif.h>
#include <csl_chip.h>
#include <stdio.h>
#define UART_BASE_ADDR 0x200008 // UART寄存器地址
/*异步通信接口芯片INS 8520 内部寄存器*/
#define RHR *((int *)(UART_BASE_ADDR+0))
#define THR *((int *)(UART_BASE_ADDR+0))
#define IER *((int *)(UART_BASE_ADDR+1))
#define ISR *((int *)(UART_BASE_ADDR+2))
#define FCR *((int *)(UART_BASE_ADDR+2))
#define LCR *((int *)(UART_BASE_ADDR+3))
#define MCR *((int *)(UART_BASE_ADDR+4))
#define LSR *((int *)(UART_BASE_ADDR+5))
#define MSR *((int *)(UART_BASE_ADDR+6))
#define SCR *((int *)(UART_BASE_ADDR+7))
#define DLL *((int *)(UART_BASE_ADDR+0))
#define DLM *((int *)(UART_BASE_ADDR+1))
#define DLL_DATA 0x48//定义UART分频系数,在11.05926M时,波特率为9600BPS
#define DLM_DATA 0x00
CSLBool b;
Uint16 eventId0;
int old_intm;
interrupt void int0(void);//外部中断0
unsigned char str1[]={"study-kit.com "};
unsigned char str2[]={"TEL:010-82623343"};
extern void VECSTART(void);
void Delay(unsigned int nDelay);
/*锁相环的设置*/
PLL_ConfigmyConfig = {
0, //IAI: the PLL locks using the same process that was underway
//before the idle mode was entered
1, //IOB: If the PLL indicates a break in the phase lock,
//it switches to its bypass mode and restarts the PLL phase-locking
//sequence
12, //PLL multiply value; multiply 12 times
0 //Divide by 2 PLL divide value; it can be either PLL divide value
//(when PLL is enabled), or Bypass-mode divide value
//(PLL in bypass mode, if PLL multiply value is set to 1)
};
/*SDRAM的EMIF设置*/
EMIF_Config emiffig = {
0x221, //EGCR: the MEMFREQ = 00,the clock for the memory is equal to cpu frequence
// the WPE = 0 ,forbiden the writing posting when we debug the EMIF
// the MEMCEN = 1,the memory clock is reflected on the CLKMEM pin
// the NOHOLD = 1,HOLD requests are not recognized by the EMIF
0xFFFF, //EMI_RST: any write to this register resets the EMIF state machine
0x1fff, //CE3_1:CE0 space control register 1
0x00ff, //CE3_2:CE0 space control register 2
0x00ff, //CE3_3:CE0 space control register 3
0x1fff, //CE1_1:CE0 space control register 1
// Asynchronous, 16Bit
0x00ff, //CE1_2:CE0 space control register 2
0x00ff, //CE1_3:CE0 space control register 3
0x1FFF, //CE2_1:CE0 space control register 1
// Asynchronous, 16Bit
0xFFFF, //CE2_2:CE0 space control register 2
0x00FF, //CE2_3:CE0 space control register 3
0x1fff, //CE3_1:CE0 space control register 1
0x00ff, //CE3_2:CE0 space control register 2
0x00ff, //CE3_3:CE0 space control register 3
0x2911, //SDC1: SDRAM control register 1
// TRC = 8
// SDSIZE = 0;SDWID = 0
// RFEN = 1
// TRCD = 2
// TRP= 2
0x0410, //SDPER : SDRAM period register
// 7ns *4096
0x07FF, //SDINIT: SDRAM initialization register
// any write to this register to init the all CE spaces,
// do it after hardware reset or power up the C55x device
0x0131 //SDC2: SDRAM control register 2
// SDACC = 0;
// TMRD = 01;
// TRAS = 0101;
// TACTV2ACTV = 0001;
};
/*中断配置*/
void INTconfig()
{
/* Temporarily disable all maskable interrupts */
IRQ_setVecs((Uint32)(&VECSTART));
/* Temporarily disable all maskable interrupts */
old_intm = IRQ_globalDisable();
/* Get Event Id associated with External INT1(8019), for use with */
eventId0 = IRQ_EVT_INT0;
/* Clear any pending INT0 interrupts */
IRQ_clear(eventId0);
/* Place interrupt service routine address at */
/* associated vector location */
IRQ_plug(eventId0,&int0);
/* Enable INT0(8019) interrupt */
IRQ_enable(eventId0);
/* Enable all maskable interrupts */
IRQ_globalEnable();
}
voiddelay(unsigned int d_time)
{
while(d_time--);
}
main()
{
unsigned int temp,data,i,k;
/*初始化CSL库*/
CSL_init();
/*EMIF为全EMIF接口*/
CHIP_RSET(XBSR,0x0a01);
/*设置系统的运行速度为144MHz*/
PLL_config(&myConfig);
/*初始化DSP的EMIF*/
EMIF_config(&emiffig);
INTconfig();
/*UART初始化*/
LCR = 0x80; //设置波提率 通信线路控制寄存器
temp=LCR; //通信线路控制寄存器
DLL = DLL_DATA;//写除数低8位
DLM = DLM_DATA;//写除数高8位
temp=DLL_DATA;
LCR = 0x00; //设置通信的数据格式,D7=0
LCR = 0x03; //8位数据,一个停止位
FCR = 0x00; //FIFO控制寄存器,在非FIFO模式
MCR = 0x08; //调制解调控制寄存器,OUT2=1,中断信号可通过系统总线送给8520中断控制寄存器
IER = 0x00; //中断使能寄存器禁止,4种中断都禁止
while(1)
{
/*发送字符串*/
/*for(k=0;k<16;k++)
{
THR=str1;
delay(200);
}
for(k=0;k<16;k++)
{
THR=str2;
delay(200);
}
delay(5000); */
temp=LSR; //通信线路状态寄存器
data=ISR; //中断识别寄存器,判别中断的类型 ,但是从下面的代码中,不明白它的作用体现在哪条语句?
THR =0x55;//发送保持寄存器,要发送的数据是U,对应16进制ASCII
if(temp&0x01)
{
data=RHR; //发送的字符已到达接收缓冲寄存器
THR=data;
temp=0;
}
delay(5000);
}
}
void Delay(unsigned int nDelay)
{
int ii,jj,kk=0;
for ( ii=0;ii<nDelay;ii++ )
{
for ( jj=0;jj<1024;jj++ )
{
kk++;
}
}
}
//External INT0(EXINT)中断处理函数
interrupt void int0()
{
unsigned int temp,data,i;
temp=LSR;
data=ISR;
if(temp&0x01)//LSR的最低位不为0,表示数据已经准备好接收
{
data=RHR;//接收保持寄存器的值送到发送保持寄存器
THR=data;
temp=0;
}
}
/******************************************************************************\
* End of UART.c
\******************************************************************************/
不明白的地方有:
1)IER = 0x00; 中断都禁止了,又怎么产生中断?
2)while中的temp应该是只能检测到LSR的第0位DR的状态,为1表示接受数据准备好,当中断使能时,这时候是不是应该进入中断的?这里if语句的功能是什么?
3)中断程序中,ISR的作用体现在哪里,似乎没用到?while程序和中断程序为什么是一样的代码,中断中应该是字符的写入或者从接受缓冲寄存器中读数据,那while中语句又是什么意思?
感觉原理明白了,但是结合到代码,又有好多疑问,没想通。 用到了 8520 不懂帮忙顶 zhangmangui 发表于 2014-3-19 21:27 static/image/common/back.gif
用到了 8520 不懂帮忙顶
这个只是自己在网上查的计算机串口通讯的资料,实际上DSP 中用的不是这个芯片,是sp3232,原理是一样的,我没有改过来。我的问题是代码部分,版主不要被8520欺骗了,希望指点。 ttxs_2013 发表于 2014-3-19 22:44 static/image/common/back.gif
这个只是自己在网上查的计算机串口通讯的资料,实际上DSP 中用的不是这个芯片,是sp3232,原理是一样的, ...
明天帮你找找相关代码 :L先看看再说。 1)IER = 0x00; 中断都禁止了,又怎么产生中断?
答:我不明白,为什么不放在系统时钟配置完之后,放在这里确实禁止中断。只是,我们一般可以通过中断初始化来开始,所以,感觉这里应该有个逻辑错误。
2)while中的temp应该是只能检测到LSR的第0位DR的状态,为1表示接受数据准备好,当中断使能时,这时候是不是应该进入中断的?这里if语句的功能是什么?
答:如果按照上一步正确的思想,这里有一种轮循的意思(好像是这样),不停的判断当前接收数据的状态,如果数据成功接收,表明接收FIFO中已经存在数据,LSR被置位,软件将数据从FIFO中读取出来。
3)中断程序中,ISR的作用体现在哪里,似乎没用到?while程序和中断程序为什么是一样的代码,中断中应该是字符的写入或者从接受缓冲寄存器中读数据,那while中语句又是什么意思?
答:一个是中断接收, 一个是轮循接收。这个要看情况的,中断比较浪费资源,轮循数据接收一旦快了,感觉会丢帧,但是接收能力,个人感觉比中断厉害。
最后,看这个代码,怎么有一种处于回环模式的感觉。8520不懂,忘指教。 pinda_ 发表于 2014-3-20 11:36 static/image/common/back.gif
1)IER = 0x00; 中断都禁止了,又怎么产生中断?
答:我不明白,为什么不放在系统时钟配置完之后,放在这 ...
按照你说的思路,我研究了下,觉得还是和代码不符:
第一个,这段代码中并没有轮循模式,因为 FCR = 0x00 是在非FIFO模式
第二个,如果说有轮循的话,参考资料对轮循的解释是:FIFO轮循模式—FIFO使能而相关的中断被禁止,CPU通过轮循状态位来检测事件。而我也把代码按照此模式改动了下,即FCR=0x01,IER=0x00,但是调试时,没有结果。
第三个,关于while和interrupt代码一样,你的解释是一个是中断接受,一个是轮循接收,但我觉得既然有中断的,那轮循不是多余 的,用一个不就就够了,并且也和第二点的FIFO轮循模式的解释相矛盾。
沿着楼主说的FIFO,轮循,参考了下资料,试着把代码改成 FIFO的中断模式(FIFO被使能而相关的中断也被使能,在事件发生时向CPU发送中断),基于此,代码改为:FCR=0x01,IER=0x07(四种中断都打开),结果也能够接受到数据。原代码中断禁止并且在非FIFO模式,同样接受成功,感觉很奇怪。
此外,还想请教楼主的是:
data=ISR ,当有中断使能,中断事件发生,ISR被置位,于是请求CPU执行中断程序,但是在If语句中为什么也是把RHR幅值给data,if中的data可以改成其他的变量吗?
还有,如果if语句是表示从接受缓冲寄存器中读数据,那么数据最终会读到哪里去?代码中是从接受缓冲到发送保持,为什么?
还有当发送移位寄存器为空,应该发送写中断,重新写入下一个字符,那么写入字符又是从哪里写入的?中断中肯定是既有写也有读,但是代码是一样的,难道也是从接受缓冲到发送保持?
以上只是我自己的理解,不知道对不对,还望楼主指教! ttxs_2013 发表于 2014-3-20 22:58 static/image/common/back.gif
按照你说的思路,我研究了下,觉得还是和代码不符:
第一个,这段代码中并没有轮循模式,因为 FCR = 0x00 ...
首先,我确实对8520不是很懂,那些寄存器相关的说明,不是很明白。只是根据你这个代码(原来是来自网上例程,刚刚看到)来分析罢了。。。
第一,当每次只发一个数据的时候,为什么要把FIFO打开,浪费了。。。我的理解是FIFO有点类似DMA的功能,看发送数据的多少才去决定,要不要使用它。
第二,根据你之前说的 “ LSR的第0位DR的状态,为1表示接受数据准备好,”,那么,temp时时会对数据接收状态进行判断,这不是轮循模式?如果不是,关于LSR的状态说明本身就是错的。
第三,这个代码是网上的,一般网上的例程都包含多个功能,如果是官方提供的,它会注释。如果不是官方的,那么我也无法解释。(最好的方法,把中断去掉,做轮循测试;再把WHILE中IF相关的去掉,测中断,分开来尝试下,理论的分析,永远也没用,要动手试试,独立开来)
最后,我上面说了,这是回环模式,也就是自己发送自己接收,这是全双工下,很好用的调试方法,好像也就UART用用吧。发送写中断,我没有看到,不明白你说的意思。
再再最后,澄清下,我不是楼主,你才是楼主,哈哈。还望指教。
ttxs_2013 发表于 2014-3-20 22:58 static/image/common/back.gif
按照你说的思路,我研究了下,觉得还是和代码不符:
第一个,这段代码中并没有轮循模式,因为 FCR = 0x00 ...
补充,中断接收与轮循接收同时存在时,程序进入中断接收,接收完后,该状态寄存器被复位,那么,也就进不了轮循了。 pinda_ 发表于 2014-3-21 09:19 static/image/common/back.gif
补充,中断接收与轮循接收同时存在时,程序进入中断接收,接收完后,该状态寄存器被复位,那么,也就进不 ...
首先得说明下,你的思路的确是正确的,只是例程本身就有些误人子弟。按照你说的调试方法,我分别测试了
UART工作模式 代码改动 测试结果
1 FIFO轮循模式 FCR=0x01,IER=0x00 不变) 数据接收正常
2 非FIFO模式 FCR=0x00,IER=0x07(四中中断打开)
while中的if语句注释掉 数据接收正常
3 FIFO中断模式 FCR=0x01,IER=0x00,,while中if注释掉 数据接收正常
实际上这三种测试,是建立在FCR和IER理论上【理论上IER=0x00,中断就是禁止的,FCR=0x00,就是在非FIFO模式】设置的,但是我把IER注释掉,上述测试同样可以。所以感觉是 :提供的例程中FCR和IER的设置是有问题的,至于为什么测试结果还很理论上的实验验证一样,不知道是没有找到合理的解释还是什么原因,这也是我之前说和代码不符的原因!
同时我也明白了while中if语句的作用,其实就是数据到达接受缓冲寄存器后,你想要进行什么控制,比如还可以 用外设显示接受到的字符,就是你说的全双工通信,发的同时,也可以接收来自串口的数据
但是还存在两个问题:
(1) 我让串口发送一个字符串,DSP 接受后在液晶上显示,起初显示的是乱码,后来换成其他字符串时,头两个字符是错的,其他的正常,在换成数字字符串时,中间的有两个是错的,其他的也是对的。想请教下,这是什么原因?是波特率问题?还是代码有问题?
(2)我把轮循模式禁止,while中if语句注释掉,只在中断模式下,同样的想让接受到的字符在液晶上显示,但是发送后,液晶上没有任何显示。代码是和轮循模式一样的,只不过是放在中断中,似乎中断中的语句并没有执行!因为printf语句就没有输出。
interrupt void int0()
{
unsigned int detect,flag,temp;
detect=LSR;
if(detect&0x01)//从LSR检测相应的状态位,进入到中断里,进一步判断中断的类型
{
lcd_display( );
printf(" lcd display");
}
if(detect&0x20)//发送移位寄存器为空
{
THR=0x55;
printf("write data:%x",THR);
}
detect=0;
}
是自己对中断模式下的UART理解错误? (1)关于发送后接收出错,你不可能一次大批量的发送数据,所以不存在波特率的问题。感觉像是电平逻辑芯片那边有问题,你先试着在代码里写一些错误寄存器的出错状态检测,看看,有没有错误发生,再去判断硬件上的问题。
(2)DEBUG下慢慢调吧,单步什么的都可以,中断进不了,那就只能看看总线上有没有执行过相应的状态。
UART中断,我的理解是:
它有一个发送FIFO寄存器与发送状态寄存器,另一个接收FIFO寄存器与接收状态寄存器,先把UART的中断打开 ,然后,硬件会通过状态寄存器中的值来判断是否有数据进来,是根据中断还是查询的方式,然后再去读写数据操作。(写的简单了点。。。。。突然发现写不好。。。。。) pinda_ 发表于 2014-3-24 10:38 static/image/common/back.gif
(1)关于发送后接收出错,你不可能一次大批量的发送数据,所以不存在波特率的问题。感觉像是电平逻辑芯片 ...
按照你说的思路,调试中的确是出现了 溢出错误,代码改动的思路是每一个错误类型进行逐一检测,最后发现是溢出错误,代码如下:
if(detect&0x01) {
lcd_display( );
if(detect&0x03)
printf(" error happen!\n");
detect=0;
}
但是,关于溢出错误,有两个问题不明白:
溢出错误是怎样产生的?按照参考资料上写的,FIFO中存储的数据超过了容量,并已经被移位寄存器接受,新的数据会覆盖移位寄存器的值,数据不会送到FIFO 这里的容量就是指的触发值?新的数据不会送达FIFO,这又是什么意思?
如果指的是触发值,那么就是说发送的字符串中字符的个数超过了14个字节(程序设置是14个字节),于是,我就把字符个数改为1个或者4个,同样是显示 溢出错误,把字符换成数字字符串,个数少于14个字节,也显示溢出错误,所以就不知道溢出错误到底是什么原因造成的?
还有,明明发送的字符串中字符个数小于14个,但是在液晶上仍然显示14个字符,如果是发一个,那么第一个是对的,后面的就是乱码,而且每次后面的都不一样;发送四个,如abcd,则abcd显示出来了,后面的又是乱码。
另外,我想既然发送字符串,无论是PC 接受还是DSP接受,都是乱码,我就测了下,DSP发送字符串给串口,是否也是溢出错误,但结果没有报错。
基于以上的原因,就弄不明白,溢出错误到底是如何产生的?接受到乱码是否是溢出错误造成的?又该如何避免,使之接受正常?
(PS:原本以为串口线有问题,但换了根线,还是一样,网上也查了URAT溢出错误,但是很杂,也没有解释溢出错误的原因的帖子,所以还是来问问你)
关于串口中断,我觉得中断和轮循模式都是要检测LSR响应的位,两者哪个发生,就看中断是否使能及中断标志是否置位,如果是,那么中断和轮询都应该发生,只不过两者,具体实现怎样的操做,看代码怎么写,所以我觉得就这个程序而言不应该不会不进入中断的,现在也没有调。
zhangmangui 发表于 2014-3-19 22:49 static/image/common/back.gif
明天帮你找找相关代码
版主有没有找到其他的代码?这个例程调了一个多星期了,还是没有解决!
页:
[1]