打印

UART 程序求助

[复制链接]
7606|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kindwyw|  楼主 | 2011-8-26 21:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
群里PIC的大虾们,,下面那段UART程序通信不上,请帮忙看是否程序的问题,谢谢!
/**********************************************
File name              :30f2010.c
Chip type              :Dspic30f2010
edition                :1.0
Program type           :Application
Clock frequency        :20.000000MKz
Memory model           :Small
External SRAM size     :512
Data Stack size        :1024
**********************************************/
#include"p30f2010.h"
#include<stdio.h>
#define uint unsigned int
#define uchar unsigned char
#define RB2 PORTBbits.RB2               //发送指示灯控制端口
#define RB3 PORTBbits.RB3               //接收指示灯控制端口
#define RB4 PORTBbits.RB4               
#define FERR U1STAbits.FERR              //帧错误位
#define PERR U1STAbits.PERR              //奇偶校验错误位
#define OERR U1STAbits.OERR              //接收缓冲器溢出状态位
#define RX_BUFFER_SIZE 8                 //接收缓冲区大小
#define TX_BUFFER_SIZE 8
uchar rx_buffer[RX_BUFFER_SIZE];          //定义接受缓冲区
uchar tx_buffer[TX_BUFFER_SIZE];
uchar rx_wr_index,rx_rd_index,rx_counter;          //写指针,读指针,存放在队列中已接收到的字符个数
uchar rx_temp,tx_remp,tx_counter,tx_rd_index;
uint rec_counter,kgbzw,pwmbzw,spwmbzw,lampbzw,lampsum,key,t1_counter,timesum,pwm_temp;
uint rx_buffer_overflow;                   //接收缓冲区溢出标志
/*****************************延时程序***********************************/
void delay(uint x)
{
uint a,b;        
for(a=x;a>0;a--)
  for(b=1250;b>0;b--);
}
/****************************UART初始化子程序*********************/
void init_UART(void)
{
     U1MODE=0X8080           ;   //使能UART模块,8个数据位,一个停止位
     U1STA=0X14C0            ;   //状态控制寄存器
     U1BRG=129               ;   //((FCY/16)/BAUD)-1 =129.21设置波特率=BAUD
     
     IPC2bits.U1TXIP = 5     ;   // 设置uart1发送接收中断优先级为5
     IPC2bits.U1RXIP = 5              ;     // 设置uart1接收中断优先级为5
     U1STAbits.UTXEN=1       ;               //发送使能

     IEC0bits.U1TXIE=1       ;              //发送中断使能
     IEC0bits.U1RXIE=1       ;              //接收中断使能
     //IFS0bits.U1TXIF = 0     ;              // 清UART1发送中断标志位
     //IFS0bits.U1RXIF = 0     ;              // 清UART1接收中断标志位
}
/****************************接收中断服务程序*******************/
void __attribute__((__interrupt__)) __U1RXInterrupt(void)
{
     uchar status,data;
     status=U1STA;                             // 读取接收状态标志位,必须先读,当读了RXREG后,U1STA就自动清零
     data=U1RXREG;                            //读取数据接收缓冲寄存器
     RB3=1;                                   //接收指示灯亮
     
                                              //判断收到字符是否有数据帧、校验或数据溢出错误
     if((status&(FERR|PERR|OERR))==0)
     {
        rx_buffer[rx_wr_index]=data;          //将字符填充到接收缓冲队列中
        if(++rx_wr_index==RX_BUFFER_SIZE)     //指针指向下一单元,并判断是否到队列的尾部
                                              //(不表示接收缓冲区是否满)
            rx_wr_index=0;                    //到了尾部,指向头部(构成环状)
             if(++rx_counter==RX_BUFFER_SIZE)  // 队列中收到字符加1,并判断是否队列已满
               {                               //队列满了
                   rx_counter=0;               //队列中收到字符个数为0,表示队列中所有以前的数据作废,
                                               //这是因为最后数据已经把前面数据覆盖了
                   rx_buffer_overflow=1;       //置位溢出标志,在主程序中必要地
                                               //方需要判断该标志,一证明所读数据的完整性
                   RB3=0;                      //接收指示灯灭
                 }
                }

}
void RX_LED_ON(void)
{
      RB3=1;               //接收灯亮
      delay(500);           //延时500ms
      RB3=0;
}

/****************************发送中断服务程序*******************/
void __attribute__((__interrupt__)) __U1TXInterrupt(void)
{
       if(tx_counter)
       {                                                         //发送队列中还有未发送的数据
        
           --tx_counter;                                        //末发送数据减1
           U1TXREG=tx_buffer[tx_rd_index];                          //发送一个数据
           if(++tx_rd_index==TX_BUFFER_SIZE) tx_rd_index=0;     //读指针指向下一个未发送的数据,
                                                                //如果指到了队列尾部,则回到队列头部
       }
  
}
/***************** MAIN ROUTINE(主程序)**************************/
int main()
{  
   init_UART();
    while(1)
    {
    }
}
沙发
yewuyi| | 2011-8-26 22:50 | 只看该作者
这个程序没法看,只能用惨字形容.

在U1TXInterrupt中,使用了 if(tx_counter)这样的结构,这可绝顶的坏事分子,具体怎么坏,自己想想,想出点名堂再讨论才能继续下去.
不管是发送接受程序, 似乎都没有处理收发中断的触发标志,反正俺是没看到.

使用特权

评论回复
板凳
kindwyw|  楼主 | 2011-8-27 14:52 | 只看该作者
谢谢楼上兄弟提醒,忘了在中断里加IFS0bits.U1TXIF = 0     ;              // 清UART1发送中断标志位
     //IFS0bits.U1RXIF = 0               // 清UART1接收中断标志位
还有请问if(tx_counter)结构有什么不妥,请赐教,谢谢

使用特权

评论回复
地板
yewuyi| | 2011-8-27 14:57 | 只看该作者
if(tx_counter)会造成MCU被这个任务独占,其它任务无法及时的响应,至于会造成何种影响,那要看具体的应用了。

此乃coding之大忌。

使用特权

评论回复
5
kindwyw|  楼主 | 2011-8-28 20:17 | 只看该作者
谢谢楼上大哥,那请看如下最简单的程序是否可以:
/****************************UART初始化子程序*********************/
void init_UART(void)
{
     U1MODE=0X0000           ;   //使能UART模块,8个数据位,一个停止位
     U1STA=0X1000            ;   //状态控制寄存器

     U1BRG=129               ;   //((FCY/16)/BAUD)-1 =129.21设置波特率=BAUD
     
     IPC2bits.U1TXIP = 5     ;   // 设置uart1发送接收中断优先级为5
     IPC2bits.U1RXIP = 5              ;     // 设置uart1接收中断优先级为5

     U1STAbits.UTXEN=1       ;               //发送使能

     IEC0bits.U1TXIE=1       ;              //发送中断使能
     IEC0bits.U1RXIE=1       ;              //接收中断使能

     IFS0bits.U1TXIF = 0     ;              // 清UART1发送中断标志位
     IFS0bits.U1RXIF = 0     ;              // 清UART1接收中断标志位

     U1MODEbits.UARTEN = 1;        // And turn the peripheral on
     U1STAbits.UTXEN = 1;
}
/****************************接收中断服务程序*******************/
void __attribute__((interrupt, no_auto_psv))  __U1RXInterrupt(void)
{
      data = U1RXREG;
      IFS1bits.U1RXIF = 0;
}
/****************************发送中断服务程序*******************/
void __attribute__((interrupt, no_auto_psv))  __U1TXInterrupt(void)
{
       IFS1bits.U1TXIF = 0;
}

使用特权

评论回复
6
yuan20082002| | 2011-8-28 21:24 | 只看该作者
PIC的中断标志只可读,不可写!!你千万不要在中断清零中断标志

使用特权

评论回复
7
yewuyi| | 2011-8-29 08:14 | 只看该作者
PIC的中断标志只可读,不可写!!你千万不要在中断清零中断标志
yuan20082002 发表于 2011-8-28 21:24



岂有此理。。。;P

你记错了吧。。。

使用特权

评论回复
8
kindwyw|  楼主 | 2011-8-29 13:44 | 只看该作者
U1STAbits.UTXEN = 1;程序一运行到这里就复位,请问是什么原因哟,谢谢

使用特权

评论回复
9
yewuyi| | 2011-8-29 16:37 | 只看该作者
U1STAbits.UTXEN = 1;程序一运行到这里就复位,请问是什么原因哟,谢谢
kindwyw 发表于 2011-8-29 13:44


1、检查看门狗。
2、检查堆栈是否溢出

使用特权

评论回复
10
kindwyw|  楼主 | 2011-8-29 20:57 | 只看该作者
看门狗关闭了,

使用特权

评论回复
11
virtualtryon| | 2011-8-29 22:37 | 只看该作者
这样做我觉得是可以的,中断实际上是一个任务,主程序也是一个任务,如果是主程序与中断共用资源,比如变量。
就会有资源互斥的问题,在你的程序中,tx_counter等变量应该在主程序中也有用到,因此会有冲突,所以要加一个标志位,保证两个任务共用一个资源时的排它性,比如中断接收完成标志,在中断接收完之前,只由中断处理,在中断接收完以后,只由主程序处理。
中断接收标志一定要在中断里面清,除非是硬件自动清的中断标志,比如串口接收中断标志,从串口缓存读出数据以后,会自动清零等等,中断发送标志也是硬件自动清的。
如果软件清的标志没有清的话,在中断退出以后,总中断使能标志会自动置1,这样又会马上进中断。那就没时间处理主程序,一直跑中断了。

使用特权

评论回复
12
yewuyi| | 2011-8-30 08:32 | 只看该作者
这样做我觉得是可以的,中断实际上是一个任务,主程序也是一个任务,如果是主程序与中断共用资源,比如变量。
就会有资源互斥的问题,在你的程序中,tx_counter等变量应该在主程序中也有用到,因此会有冲突,所以要 ...
virtualtryon 发表于 2011-8-29 22:37



保证代码不出现临界代码是一个代码操作工的最基本职责。

使用特权

评论回复
13
兰天白云| | 2011-8-30 10:16 | 只看该作者
yewuyi真是敬业,LZ算你运气好,遇到名师

使用特权

评论回复
14
virtualtryon| | 2011-8-30 12:17 | 只看该作者
保证代码不出现临界代码是一个代码操作工的最基本职责。
yewuyi 发表于 2011-8-30 08:32

弱弱地问一下,什么是临界代码?能否举个例子.

使用特权

评论回复
15
kindwyw|  楼主 | 2011-8-30 21:20 | 只看该作者
问题还在纠结中,在这里先谢谢楼上几位兄台了,特别是要感谢敬业的yewuyi大师耐心的回复,谢谢!谢谢

使用特权

评论回复
16
yewuyi| | 2011-8-31 08:47 | 只看该作者
弱弱地问一下,什么是临界代码?能否举个例子.
virtualtryon 发表于 2011-8-30 12:17



临界代码的实例有很多种形式,最容易犯的一个形式就是你在11楼的举例,所以,例子你已经自己给出,俺就没必要举了。


临界的意思用白话翻译就是:在一定的条件下,某些代码可能执行,也可能不执行,具体是否执行,要看条件是否满足,而执行的结果中有一些结果并不是程序员所期望的。

具体你可以看OS方面的书籍,或者百度一下这个名词。

使用特权

评论回复
17
virtualtryon| | 2011-8-31 08:58 | 只看该作者
本帖最后由 virtualtryon 于 2011-8-31 09:02 编辑

在多用户系统上,多进程系统上,通常程序中存在部分临界代码。我们需要确保只有一个进程或执行线程进入临界代码并拥有对资源独占式的访问权。   不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。每个进程中访问临界资源的那段代码称为临界区(Critical Section)。   每个进程中访问临界资源的那段程序称为临界区(Critical Section)(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入。不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
是这个吧?没有看到不允许临界代码?
我觉得对于低端的单片机,处理能力有限,资源访问做到互斥才不会有问题.

使用特权

评论回复
18
yewuyi| | 2011-8-31 09:03 | 只看该作者
在多用户系统上,多进程系统上,通常程序中存在部分临界代码。我们需要确保只有一个进程或执行线程进入临界代码并拥有对资源独占式的访问权。   不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进 ...
virtualtryon 发表于 2011-8-31 08:58


这些是网络上百度的吧。
呵呵,这些是针对PC端而言的,但对于MCU是一样适用,只是没有多用户。:D

使用特权

评论回复
19
virtualtryon| | 2011-8-31 09:14 | 只看该作者
这些是网络上百度的吧。
呵呵,这些是针对PC端而言的,但对于MCU是一样适用,只是没有多用户。:D
yewuyi 发表于 2011-8-31 09:03

LZ说的是PC机,资源无限大。而且都是跑多线程的,如果互斥了肯定会影响其他的进程。
但是,我觉得MCU如果访问共享资源不互斥的话,更会出问题.
引用某大车厂的一个标准。
为避免破坏这些资源或者是其返回的数据的完整性,在单个MCU中被多个任务共享的资源(比如:变量,非易失存储器,寄存器,I/O口等等必须控制对其的访问(通常是通过相互排斥)

使用特权

评论回复
20
ldk060| | 2011-9-1 09:39 | 只看该作者
我正在学PIC呢 帮忙顶下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

55

帖子

2

粉丝