搜索
bottom↓
回复: 3

求教一个关于ATMEGA16L串行通信的奇怪问题?

[复制链接]

出0入0汤圆

发表于 2014-8-6 01:59:07 | 显示全部楼层 |阅读模式
先上代码:
usart.h
#ifndef __USART_H__
#define __USART_H__

#include <ioavr.h>

#define USART_BAUD_9600     47
#define USART_BAUD_19200    23

#define USART_TX_BUFFER_SIZE    16
#define USART_RX_BUFFER_SIZE    16

void USART_Init( void );
void USART_TransmitByte( unsigned char _data );
void USART_TransmitBuffer( unsigned char *_ptr );
unsigned char USART_ReceiveByte( void );

#endif

usart.c

#include "global_cfg.h"
#include "usart.h"

volatile unsigned char usart_rx_buffer[USART_RX_BUFFER_SIZE];
volatile unsigned char usart_rx_wr_index, usart_rx_rd_index, usart_rx_counter;
volatile unsigned char usart_rx_buffer_overflow;

volatile unsigned char usart_tx_buffer[USART_TX_BUFFER_SIZE];
volatile unsigned char usart_tx_wr_index, usart_tx_rd_index, usart_tx_counter;

void USART_Init(void)
{
    UBRRH = 0;
    UBRRL = USART_BAUD_9600;     
   
    UCSRA = 0x00;
    UCSRB_RXEN = 1;
    UCSRB_TXEN = 1;
    UCSRB_RXCIE = 1;
    UCSRB_TXCIE = 1;
    //UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE) | (1 << TXCIE);
    UCSRC_URSEL = 1;
    UCSRC_UCSZ1 = 1;
    UCSRC_UCSZ0 = 1;
    //UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
   
    usart_rx_wr_index = 0;
    usart_rx_rd_index = 0;
    usart_rx_counter = 0;
    usart_rx_buffer_overflow = 0;
    usart_tx_wr_index = 0;
    usart_tx_rd_index = 0;
    usart_tx_counter = 0;
}

unsigned char USART_ReceiveByte( void )
{
    unsigned char data = 0;
    //接收数据队列中没有数据可以读取,等待......
    while( usart_rx_counter == 0 );
    //读取缓冲队列中的数据
    data = usart_rx_buffer[usart_rx_rd_index];
    //读取指针指向下一个未读的数据,如果指到了队列尾部,则指回到队列头
    if( ++usart_rx_rd_index == USART_RX_BUFFER_SIZE )
        usart_rx_rd_index = 0;
   
    CLI();
    //队列中未读数据个数减1。
    //因为该变量在接收中断中要改变的,为了防止冲突,所以改动前临时关闭中断。程序相当可靠了。
    --usart_rx_counter;
    SEI();
   
    return data;
        
}

void USART_TransmitByte( unsigned char _data )
{
    //发送数据队列中还有数据没有发送完,等待
    while( usart_tx_counter == USART_TX_BUFFER_SIZE);   
    CLI();
    //若发送数据队列有数据或者数据寄存器UDR非空时执行
    //(因为队列先进先出的原因,所以,c要放进非空的发送数据队列里面)
    if( usart_tx_counter || UCSRA_UDRE == 0 )
    {
        usart_tx_buffer[usart_tx_wr_index] = _data;
        if( ++usart_tx_wr_index == USART_TX_BUFFER_SIZE )
            usart_tx_wr_index = 0;
        ++usart_tx_counter;
    }
    else
        UDR = _data;
    SEI();
}

void USART_TransmitBuffer( unsigned char *_ptr )
{
    while (*_ptr)
    {
        USART_TransmitByte(*_ptr++);
    }
    USART_TransmitByte(0x0D);
    USART_TransmitByte(0x0A);  //结尾发送回车换行   
}

#pragma vector = USART_RXC_vect
__interrupt void USART_RXC_interrupt( void )
{
    unsigned char status, data;
    //读取接收状态标志位,必须先读,当读了UDR后,UCSRA便自动清零了
    status = UCSRA;
    //读取USART数据寄存器
    data = UDR;
   
    //判断本接收到的数据是否有数据帧、校验或数据溢出错误(此处指USART的硬件接收溢出)
    if( status & ( ( 1 << FE ) | ( 1 << PE ) | ( 1 << DOR ) ) == 0 )
    {
        //将数据填充到接收缓冲队列中
        usart_rx_buffer[usart_rx_wr_index] = data;
        //写指针指向下一个单元,并判断是否到了队列的尾部
        if( ++usart_rx_wr_index == USART_RX_BUFFER_SIZE )
            //到了尾部,则指向头部
            usart_rx_wr_index = 0;
        //队列中收到字符加1,并判断是否队列已满
        if( ++usart_rx_counter == USART_RX_BUFFER_SIZE )
        {
            //队列满了,队列中收到字符个数为0,表示队列中所有以前的数据作废,
            //因为最后的数据已经把最前边的数据覆盖了
            usart_rx_counter = 0;
            //置缓冲区溢出标志。在主程序中必要的地方需要判断该标志,以证明读到数据的完整性
            usart_rx_buffer_overflow = 1;
        }
    }
}

#pragma vector = USART_TXC_vect
__interrupt void USART_TXC_interrupt( void )
{
    if( usart_tx_counter )
    {
        --usart_tx_counter;
        UDR = usart_tx_buffer[usart_tx_rd_index];
        if( ++usart_tx_rd_index == USART_TX_BUFFER_SIZE )
        {
            usart_tx_rd_index = 0;
        }
    }
}

这是参考cvavr给出的串口通信例子。我把它修改为IAR EWAVR 5.4下可编译,运行的代码。主程序如下:
#include "global_cfg.h"
#include "delay.h"
#include "usart.h"

unsigned char g_aTXBuffer[29] = {0xAA,0x98,0x00,0xC8,0x00,0xC8,0x00,0x80,0x05,0xF8,0x00,0x00,0x00,0xC9,0xEE,0xDB,0xDA,0xB2,0xCA,0xBE,0xA7,0xBF,0xC6,0xBC,0xBC,0xCC,0x33,0xC3,0x3C};

void main(void)
{
    CLI();
    USART_Init();
    SEI();
   
    DELAY_Seconds(2);
   
    unsigned char i = 0;
   
    for( i = 0; i < 29; i++)
    {
        USART_TransmitByte(g_aTXBuffer[i]);
    }
    //USART_TransmitBuffer( "Hello" );   
    while(1)
    {
    }
}

这个测试程序在ATMEGA128-16AU的最小系统上可以运行,无错误。但是整个程序放到一个ATMEGA16L的电路板上却运行不了,目标板不工作,用串口通信助手测试,发现收到的全是0.
ATMEGA16L的电路板和目标板可以进行串行通信,我用从教科书上抄来的一段代码测试过,可以正确传输数据。
彻底凌乱了,请高手指点一二。

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2014-8-6 02:15:30 | 显示全部楼层
硬件故障?            

出0入0汤圆

 楼主| 发表于 2014-8-6 09:35:49 | 显示全部楼层

串口能工作啊!用另外一个程序可以工作,我就是把原来的程序改写了一下。。。

出0入0汤圆

 楼主| 发表于 2014-8-20 09:52:49 | 显示全部楼层
偶然发现了这个问题的原因:我的IAR AVR 5.4不知为何在ATMEGA16上无法编译多个C文件。。。在ATMEGA128却可以。。。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-3 09:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表