基于AT91SAM7se512的串口通讯的实现

来源:互联网 发布:点点客人人店登陆端口 编辑:程序博客网 时间:2024/06/07 05:13

实验室正在研究基于AT91SAM7se512芯片的无人机系统和基于SImulink的无人机飞行仿真平台,主控制芯片与外围传感器的通讯和主控芯片与PC机的通讯是本项目最基本的部分,下面将此段时间对串口通信的认识记录下来,由于本人知识水平的有限,欢迎各位读者积极指正,我将不胜感激。

(一)、硬件部分.

在AT91SAM7se512的串口通信过程中,我使用的是usb转串口线,单一的232串口还是不能和主控芯片连接的,因为二者的电平不一样,232的电平为:高电平=-(3~15)V,低电平=+(3~15)V,而主控芯片的电平为TTL电平,高电平=3V,低电平=0V。所以在串口通信中,必须使用一块232电平转TTL电平的芯片,这里采用的是ADM3202,ADM3202是四通道的TTL转RS232电平的芯片。

由于AT91SAM7se512的两个串口在系统中已经使用,这里选择DBGU口的串口功能做的实验。

(二)、软件的实现

因为在串口发送和接收过程中,中断方式有利于提高cpu的利用率,所以在此选择中断方式。

2.1 初始化

在串口的初始化程序中,需要对串口的IO引脚分配、电源管理、串口配置、AIC中断配置和使能、PDC的设置和DBGU中断的使能进行设置。初始化程序如下所示:

void AT91F_DBGU_Simulink_Init(void){  AT91F_DBGU_CfgPIO();  AT91F_DBGU_CfgPMC();  AT91F_US_Configure ((AT91PS_USART)AT91C_BASE_DBGU, AT91B_MCK,                          AT91C_US_ASYNC_MODE,115200, 0);   AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;  AT91F_AIC_ConfigureIt (AT91C_BASE_AIC, AT91C_ID_SYS, DBGU_USART_INTERRUPT_LEVEL,                          AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, Debug_Simulink_irq_handler);  AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_SYS);      // Set the PDC    AT91F_PDC_Open (AT91C_BASE_PDC_DBGU);    //* address to the next bloc to be received    AT91C_BASE_DBGU->DBGU_RPR = (unsigned int) simulink_queue;    AT91C_BASE_DBGU->DBGU_RCR = SIMULINK_NUM;//* 137个字符    //*  and AT91C_US_ENDRX    AT91F_DBGU_InterruptEnable(AT91C_BASE_DBGU,AT91C_US_RXBUFF  );//* RX Buffer Full Interrupt Enable                                              // 字符串形式}
以上各个函数和参数在lib_AT91SAM7se512.h、T91SAM7se512.h中定义的,Debug_Simulink_irq_handle为中断服务程序,simulink_queue和SIMULINK_NUM为接收缓冲区及其大小,在此使用的中断触发为RXBUFF(接收缓冲区满)和TXBUFE(发送缓冲区空),RXBUFF中断在初始化中使能,而TXBUFF中断在主函数中使能,稍后会有讲解。

2.2中断服务程序
中断服务程序Debug_Simulink_irq_handle如下:

void Debug_Simulink_irq_handler(void){AT91PS_DBGU USART_pt = AT91C_BASE_DBGU;unsigned int status;//* get Usart status register and active interruptstatus = USART_pt->DBGU_CSR ;//获得通道状态        status &= USART_pt->DBGU_IMR;//去掉屏蔽的状态if ( status & AT91C_US_RXBUFF)//如果是RXBUFF,则设置DBGU_RPR和DBGU_RCR{      AT91C_BASE_DBGU->DBGU_RPR = (unsigned int) simulink_queue;     AT91C_BASE_DBGU->DBGU_RCR = SIMULINK_NUM;             simulink_flag=1;            }                if ( status & AT91C_US_TXBUFE)//如果是TXBUFE,则设置DBGU_TPR和DBGU_TCP{               AT91F_DBGU_InterruptDisable(AT91C_BASE_DBGU,AT91C_US_TXBUFE  );              to_simulink_transmit_flag=true;              AT91C_BASE_DBGU->DBGU_TPR = (unsigned int)NULL;              AT91C_BASE_DBGU->DBGU_TCR = 0;         }   //* Reset the satus bit for error     USART_pt->DBGU_CR = AT91C_US_RSTSTA;//错误状态位复位} 

2.3 主函数

void main(void ){//初始化函数              for(; ; )//主循环      {           //省略若干           if (simulink_flag == 1)         {            deal_simulink_data();//处理从PC机发送到控制芯片的数据            simulink_flag = 0;         }       //省略若干       output2simulink();//发送数据到PC机      }}

其中deal_simulink_data()函数和output2simulink()函数如下:

void deal_simulink_data(void){  char save_line[SIMULINK_NUM],*line=NULL;// 不指空 死机?  strncpy( save_line, simulink_queue,SIMULINK_NUM );  line=save_line;//line指向接收到数据的存储地址   //省略若干  }

void output2simulink(void){  int len=3;  if(to_simulink_transmit_flag==true)  { //-------------------control mode------------------------------------        put2simulink[len++]=',';      put2simulink[len++]=control_mode+48;      //--------------------PWM--------------------------------------------      for(int i = 0;i < 4;i ++)      {         put2simulink[len++] = ',';           len += sprintf(put2simulink+len,"%4d",sim_servo_widths[i]);                }      put2simulink[len++]='\r';      put2simulink[len++]='\n';      to_simulink_transmit_flag=false;       AT91C_BASE_DBGU->DBGU_TPR = (unsigned int)put2simulink;      AT91C_BASE_DBGU->DBGU_TCR = len;      AT91F_DBGU_InterruptEnable(AT91C_BASE_DBGU,AT91C_US_TXBUFE  );//开TXBUFE中断      }}

(三)总结

使用串口调试助手即可以实现PC与ARM板的通信,如果想用其他串口来检测从PC发送到ARM的数据是否正确,检测ARM是否正常接收了由PC发送来的数据,这里有两种方法:

1 、使用IAR中的调试功能,在处理接收数据的地方加一句调试语句printf("%s",line);在Terminal I/O中可以看到输出的字符串。

2、使用其他串口将PC发送到ARM版的数据在发送到PC端,用串口调试助手既可以看到。

在以上两种方法中,我更加喜欢第二种,因为第一种的printf函数占用的调试时间太长,而第二种可以实际反应出程序运行时间情况。

在检测过程中,有几种情况可能导致数据不正确:

1、PC端与ARM板的波特率没有对应起来,这是最容易发现的,也是最容易解决的,将二者的波特率设为一样即可。

2、程序中各个缓冲区的长度不对,这是比较难找的问题,就是因为这个问题,我花了很长的时间才解决好这个问题,本以为检测用的缓冲区的定义的长度只要足够大即可,其实不然,PC端发送字符串的长度、ARM中接收缓冲区定义的长度,实际使用缓冲区的长度、ARM中另一个串口发送字符串的缓冲区定义的长度、实际使用的长度要一致,这里最容易忽略的地方是两个缓冲区的定义的长度,当定义的长度与实际接收的字符串的长度不同的时候,会出现周期性乱码的现象,具体原因我还不明白,希望各位高手指教。