在线时间613 小时
UID252169
注册时间2010-12-5
NXP金币0
TA的每日心情 | 开心 2019-2-14 16:49 |
---|
签到天数: 296 天 连续签到: 1 天 [LV.8]以坛为家I
金牌会员
 
- 积分
- 4473
- 最后登录
- 2020-4-14
|
本讨论仅针对MKLxxZ128xxx系列的芯片做的一些测试和实验,目的是为了弄明白Freescale——老外们[也许是国人在函数编程上的一些思路——因为函数的嵌套太多以致让人想完全弄明白则必须就是用这款芯片——这不是在设计和选芯时的好方法,有时会丢了大量的客户!!!]
2.UART的函数
MKL_uart.h的一段定义
#define MKL_UART0 0
#define UART_PARITY_EN 1
#define UART_PARITY_DIS 0
#define UART_PARITY_EVEN 0
#define UART_PARITY_ODD 1
#define UART_10BIT_LENGTH 10
#define UART_9BIT_LENGTH 9
#define UART_8BIT_LENGTH 8
#define UART_1BIT_STOP 1
#define UART_2BIT_STOP 2
#define UART_POLLED 0
#define UART_INTERRUPT 1
#define UART_DMA 2
#define UART_TX_ENABLE 1
#define UART_TX_DISABLE 0
#define UART_RX_ENABLE 1
#define UART_RX_DISABLE 0
#define UART0_DEFAULT_OPEN 1//是否允许传输 1/0
#define UART0_IRQ_ENABLE 1//串口中断允许 1/0
#define UART0_SEND_IRQ 0//1/0
#define UART0_RECEIVE_IRQ 1//1
#define UART_PARAM_DEBUG 0//是否进行参数检查
#define UART_PARAM_PORTNUM(x) (x > 3? 1 : 0)//端口号检查
#define UART_PARAM_MODE(x) (x > 3? 1 : 0)//模式检查
#define UART_PARAM_LENGTH(x) ((x == 8)||(x == 9)||(x == 9) ? 1 : 0)//数据长度检查
#define UART_PARAM_STOP(x) ((x == 1)||(x == 2)? 1 : 0)//停止位检查
#define UART_PARAM_PARITY(x) ((x == 0)||(x == 1)? 1 : 0)//校验位检查
#define UART_PARAM_LOGIC(x)((x == 0)||(x == 1)? 1 : 0)//逻辑位检查
#define UART_CHECK_PARAM(x)(x? (while (1)) //错误处理
从函数定义和后边的注视来看十分清楚明了,Ok!很好操作!接着从MKL_urat0.c
//uart0 Initial input parameters:
//ucBaudRate:波特率;ucParityEnable:校验位选择;ucParityType:校验类型;ucDataLength:数据长度;ucStopBit:停止位;
void uart0Init(INT32U ulBaudRate,INT8U ucParityEnable,INT8U ucParityType,INT8U ucDataLength,INT8U ucStopBit){
UART0_MemMapPtr uartPtr=UART0_BASE_PTR;
register INT16U usBaudRate=0;
#if UART_PARAM_DEBUG
UART_CHECK_PARAM(UART_PARAM_LENGTH(ucDataLength));//由程序输入此4个数据
UART_CHECK_PARAM(UART_PARAM_STOP(ucStopBit));
UART_CHECK_PARAM(UART_PARAM_LOGIC(ucParityEnable));
UART_CHECK_PARAM(UART_PARAM_PARITY(ucParityType));
#endif
SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;
SIM_SOPT2 |= SIM_SOPT2_UART0SRC(1);//选择PLL时钟
SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;//允许外设时钟
uart0TranControl(UART_TX_DISABLE, UART_RX_DISABLE);//首先禁止通信
#if 1
PORTA_PCR1 = PORT_PCR_MUX(0x2);//UART0_TXD ||默认首选输出I/O口
PORTA_PCR2 = PORT_PCR_MUX(0x2);//UART0_RXD ||默认首选输入I/O口
#endif
#if 0
PORTA_PCR14 = PORT_PCR_MUX(0x3);//UART0_TXD
PORTA_PCR15 = PORT_PCR_MUX(0x3);//UART0_RXD
#endif
#if 0
PORTD_PCR7 = PORT_PCR_MUX(0x3);//UART0_TXD
PORTD_PCR6 = PORT_PCR_MUX(0x3);//UART0_RXD
#endif
#if 0
PORTE_PCR20 = PORT_PCR_MUX(0x4);//UART0_TXD
PORTE_PCR21 = PORT_PCR_MUX(0x4);//UART0_RXD
#endif
#if 0
PORTE_PCR17 = PORT_PCR_MUX(0x3);//UART0_TXD
PORTE_PCR16 = PORT_PCR_MUX(0x3);//UART0_RXD
#endif //数据长度 //校验位类型 //校验位
UART0_C1_REG(uartPtr) &= ~(UART0_C1_M_MASK|UART0_C1_PT_MASK|UART0_C1_PE_MASK);
UART0_C4_REG(uartPtr) &= ~UART0_C4_M10_MASK;
if(ucDataLength==10){
UART0_C1_REG(uartPtr) |=(ucParityEnable << UART0_C1_PE_SHIFT)|(ucParityType << UART0_C1_PT_SHIFT);
UART0_C4_REG(uartPtr) |=UART0_C4_M10_MASK;
}else{
UART0_C1_REG(uartPtr) |=((ucDataLength-8UL)<<UART0_C1_M_SHIFT)|(ucParityEnable<<UART0_C1_PE_SHIFT)|(ucParityType<<UART0_C1_PT_SHIFT);
}
usBaudRate = SystemBusClock/(ulBaudRate * 16);
UART0_BDH_REG(uartPtr) = (usBaudRate & 0x1F00) >> 8;//波特率
UART0_BDL_REG(uartPtr) = (INT8U)(usBaudRate & UART0_BDL_SBR_MASK);
UART0_BDH_REG(uartPtr) &= ~UART0_BDH_SBNS_MASK;//停止位
UART0_BDH_REG(uartPtr) |= (ucStopBit - 1) << UART0_BDH_SBNS_SHIFT;
UART0_C2_REG(uartPtr) &= ~(UART0_C2_TIE_MASK|UART0_C2_TCIE_MASK|UART0_C2_RIE_MASK|UART0_C2_ILIE_MASK);//清除中断设置
while((UART0_S1_REG(uartPtr) & UART0_S1_RDRF_MASK) && (UART0_D_REG(uartPtr)));//清接收缓冲区
#if UART0_DEFAULT_OPEN
uart0TranControl(UART_TX_ENABLE, UART_RX_ENABLE);//配置完成允许通信
#endif
#if UART0_IRQ_ENABLE
#if UART0_SEND_IRQ
UART0_C2_REG(uartPtr) |= UART0_C2_TCIE_MASK;
#endif
#if UART0_RECEIVE_IRQ
UART0_C2_REG(uartPtr) |= UART0_C2_RIE_MASK;
#endif
NVIC_EnableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn,3);//用户自己定义
#endif/**/
}
从此节的函数可以明了,UART0初始化函数,但从最后10行就不明白了:
#if UART0_IRQ_ENABLE——如果UART0中断允许...
#if UART0_SEND_IRQ——如果传输中断允许...
#if UART0_RECEIVE_IRQ——如果接收中断允许...
这3条定义实在不能让人理解。中断是让人为操作和定义的,就是说需要一些中断产生的信息时开中断,当不需要中断时将中断关掉以防止影响主程序的运行,而此处是用来判断中断是否开通!——通常判断中断是否完成是为了保证读取的数据完整性,实在不明白。算了,接着看:
//ucTxEnable:发送使能控制;ucRxEnable:接收使能控制
void uart0TranControl(INT8U ucTxEnable,INT8U ucRxEnable){
UART0_MemMapPtr uartPtr = UART0_BASE_PTR;
#if UART_PARAM_DEBUG
UART_CHECK_PARAM(UART_PARAM_LOGIC(ucTxEnable));
UART_CHECK_PARAM(UART_PARAM_LOGIC(ucRxEnable));
#endif
UART0_C2_REG(uartPtr) &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
UART0_C2_REG(uartPtr) |= (ucTxEnable << UART0_C2_TE_SHIFT)|(ucRxEnable << UART0_C2_RE_SHIFT);
}
这段很明确,是UART0传输和接收控制程序,按照前边函数定义0是禁止,1是允许,设置就Ok了。再接着:
//uart0 Get Charact UART获取一个字节
INT8U uart0GetChar(void){
UART0_MemMapPtr uartPtr = UART0_BASE_PTR;
while (!(UART0_S1_REG(uartPtr) & UART0_S1_RDRF_MASK));//等待接收缓冲区可用
return UART0_D_REG(uartPtr);//返回接收字节
}
从UART0获取1个数据,返回的就是1个字节的数据,无问题,与上边的注释一致。再接着
//uart0 Send a Charact UART发送一个字节 ucData:待发送字节
void uart0SendChar(INT8U ucData){
UART0_MemMapPtr uartPtr = UART0_BASE_PTR;
while (!((UART0_S1_REG(uartPtr) & UART0_S1_TDRE_MASK)));//等待FIFO可用
UART0_D_REG(uartPtr) = ucData;//填充数据寄存器
}
发送一个字节,好像没有问题,但实际上是有问题的!一会儿再说这个问题
最后[跳过了连续发送存储区的一段]一段:
//UART0_IRQHandler UART0中断服务函数
void UART0_IRQHandler(void){
UART0_MemMapPtr uartPtr = UART0_BASE_PTR;//发送中断处理程序
#if UART0_SEND_IRQ
//while(!UART0_D_REG(uartPtr));//自加的!!!//发送中断处理程序|用户定义
#endif
#if UART0_RECEIVE_IRQ
while(UART0_S1_REG(uartPtr) & UART0_S1_RDRF_MASK){//清除中断标志UART0_S1_RDRF_MASK=0x20u
uart0SendChar(UART0_D_REG(uartPtr));//返回接收数据
//while(!UART0_D_REG(uartPtr));//清接收缓冲区 ||禁止!!!
}
#endif
}
啊,中断服务函数,前半部分说明用户写的发送用户的程序,怎么写呢?尝试了各种写法都不成功,主要原因是此处属于定义函数,在主程序中定义的变量无法在此处调用,此节定义的又无法返回到主程序,这里能有什么用呢?不清楚
第二段的uart0SendChar(UART0_D_REG(uartPtr));,如果此条开通,则接受的数据自动从TX口发送出去——就是透传了。如果注释掉此句,那么由
uart0GetChar()得到的数据,无法用uart0SendChar()从TX口发送:程序段如下:
temp=uart0GetChar();
uart0SendChar(temp);
你会发现程序毫无反应,就像对空操作一样。但如果你不注释掉uart0SendChar(UART0_D_REG(uartPtr));此句,前边的那个接收和发送就Ok!先别着急认为完了。你认为是接收了一个发送一个,还是接受几个发送几个?我做测试方法如下:
主程序循环执行:
temp=uart0GetChar();
uart0SendChar(temp);
LCD显示刷新屏幕
串口调试助手接上UART0_RX和UART_TX,测试如下:
A. 发送端输入1,结果有时发送1个1就有回应——显示屏循环刷新1次;有时需要输入两个1——显示器循环刷新1次;最多见的是输入3个1循环显示1次;好了我这样做实验:1次1个1、1次12、1次123——分别是1次输入1个、2个、3个字符,看程序如何响应,结果:
1个的,响应最少、2个的响应次之、当连续输入3个字符后,几乎每次都响应——即程序能走到连续循环刷新屏幕。
由此得出,此程序并不是1次读取1个字符和输出1个字符,从几率来说,3个字符的读取能保证中断执行1次!!!
这样的程序有用吗?在无序乱读数据中是有用——产生随机数有用,但在需要读取的数据过程中要么多读丢数据,要么少读也丢数据!!!
B. 改程序为:
temp=UART0_D;//uart0GetChar();
//uart0SendChar(temp);
LCD显示刷新屏幕
结果为无论第二句有无,程序都自动循环,说明可以实现自动收转发
C. 如果改成:
temp=UART0_D;//uart0GetChar();
//uart0SendChar(temp);
printf("\n\r"+temp);
LCD显示刷新屏幕
则在PC串口模拟器上输出的数据有变化,有时1换行23,有时123换行,有时123123才换行。并且程序受PC端TX触发影响?什么影响。
总结:
案例中的UART0程序几乎没有什么参考价值。充其量仅仅说明KL系列芯片有UART功能。
本人觉得案例是应该简洁明了,并且针对实验者具有将来编程的指导意义。否则就属于误导。
有人会说,那只是案例,你可以自己修改函数甚至会说自己去编函数!?是那样的话,人人都是编函数的天才了,走到这里的首先是初学者,可以说多数是从校门走来的,可能看都困难别说改和编写了。
仅仅希望这些编引导应用的的函数或程序能精简点, 能做到简而明了,有可以自己加点什么就能扩充功能或改变应用的可能。可爱的Freescale,在BSP的函数上不妨学学Nutoton的BSP,他们的可操作性极强,注释清楚,增加改变功能比较容易。也许,从芯片的功能来说,F有着先天优势,N后发在追,如果总是固步自封,会让人追上的。
|
|