[关闭]
@comzyh 2015-07-03T21:16:30.000000Z 字数 4107 阅读 2005

嵌入式系统大作业实验报告

Author : 张永辉
[TOC]

引脚定义

使用GPIO_H 中的两个引脚作为串口通信RX 和 TX端

数据读写宏定义:

  1. #define OUT_TXD_H() (rGPHDAT |=(1<<2))
  2. #define OUT_TXD_L() (rGPHDAT &=~(1<<2))
  3. #define GET_RXD_PIN() (rGPHDAT &(0X08))

由于GPH并没有外部中断功能,我们将GPH3GPG0并联,利用GPG0EINT8探测RX的下降沿启动接受

初始化部分

虚拟串口初始化函数:

  1. /*
  2. VirUsart_init 模拟串口初始化函数
  3. 参数:
  4. _baud 波特率
  5. _stop_bit 停止位 0 = 无, 1 = 有
  6. _parity_check 奇偶校验 0 = 无, 1 = 奇校验, 2 = 偶校验
  7. _data_width 数据位
  8. */
  9. void VirUsart_init(int _baud,int _stop_bit,int _parity_check,int _data_width)
  10. {
  11. baud = _baud;
  12. stop_bit = _stop_bit;
  13. parity_check = _parity_check;
  14. data_width = _data_width;
  15. VirUartGPIO_init();
  16. }

接口初始化函数

  1. void VirUartGPIO_init(void)
  2. {
  3. // 模拟管脚 配置
  4. rGPHCON = 0;
  5. rGPHCON |= (0x01 << 4); // GPH2 (TXD0) 输出 GPH3(RXD0) 输入
  6. rGPHUP |= (1 << 2) | (1 << 3);
  7. OUT_TXD_H(); // TXD0 高
  8. //GPG0 EINT8 配置
  9. rGPGCON = rGPGCON & (~0x1) | 0x2; //GPGCON[1:0] = 10
  10. //EINT8 下降沿触发
  11. rEXTINT1 = rEXTINT1 & (~0x4) | 0x2 ;//EXTINT1[2:0] = 01
  12. //设置中断服务程序
  13. pISR_EINT8_23 = (U32)VirUart_RX_ISR;
  14. //清空 EINTPEND中断请求
  15. rEINTPEND = 0xffffff;
  16. rSRCPND = BIT_EINT8_23; //to clear the previous pending states
  17. rINTPND = BIT_EINT8_23;
  18. //取消EINT8 中断屏蔽
  19. rEINTMASK &= ~(1 << 8);
  20. rINTMSK = ~(BIT_EINT8_23);
  21. }

发送部分

发送由时钟Timer2控制,时钟初始化函数如下

  1. //timer2 发送时钟
  2. void VirUart_Tx_TimerInit()
  3. {
  4. int time_cnt;
  5. // 计算计数常数
  6. time_cnt = PCLK / (1 * 2) / (baud);
  7. // 设置定时器配置寄存器0
  8. rTCFG0 = 0; // 预分频数值 为 0
  9. // 设置定时器配置寄存器1
  10. rTCFG1 = 0; // 分割器值 为 0 1/2PLCK
  11. // 设置计数器
  12. rTCNTB2 = time_cnt;
  13. // 设置控制寄存器
  14. rTCON &= ~(0x1f << 12);
  15. rTCON |= (0xb << 12);
  16. rTCON &= ~(2 << 12);
  17. rINTPND = rINTPND; // 清零
  18. rINTMSK &= ~BIT_TIMER2; // 打开 Timer2 中断
  19. pISR_TIMER2 = (U32)Time2_Tx_Ir;
  20. }

数据发送函数

  1. // 模拟发送数据
  2. void VirUartTxData_task(void)
  3. {
  4. static unsigned char sendnum = 0;
  5. static short check;
  6. static short mask;
  7. int i;
  8. switch (flagTx)
  9. {
  10. case 0: // 初始化
  11. flagTx = 1;
  12. break;
  13. case 1: // 等待起始信号
  14. if (NewFlagTx > 0)
  15. {
  16. mask = (1 << data_width) - 1;
  17. flagTx = 2;
  18. VirUart_Tx_TimerInit();
  19. nCountTxData = 0;
  20. if (parity_check) // 计算校验位
  21. {
  22. check = NewTxData & mask;
  23. for (i =0; i< data_width - 1; i ++)
  24. check = (check >> 1) ^ (check & 0x1);
  25. if (parity_check == 1) // 奇校验
  26. check ^= 0x1;
  27. NewTxData |= check << data_width;
  28. }
  29. OUT_TXD_L(); // 发送一个低电平 作为起始信号
  30. }
  31. break;
  32. case 2:
  33. break;
  34. case 3: // 发送完了
  35. flagTx = 1;
  36. NewFlagTx = 0;
  37. Delay( 100 ) ;
  38. NewFlagTx = 1;
  39. NewTxData = sendnum;
  40. sendnum += 3;
  41. break;
  42. }
  43. }

Timer2的中断服务程序(实际发送程序)

  1. void __irq Time2_Tx_Ir(void)
  2. {
  3. U32 r;
  4. EnterCritical(&r);
  5. if (rINTPND == BIT_TIMER2)
  6. {
  7. ClearPending(BIT_TIMER2);
  8. if (nCountTxData >= data_width + (parity_check > 0)) // 发送完成
  9. {
  10. flagTx = 3;
  11. rINTMSK |= BIT_TIMER2; // 关闭 Timer2 中断
  12. rTCON = (rTCON & (~(0x1f << 12))); //关闭 TCNTB2
  13. }
  14. else
  15. {
  16. if (NewTxData & 0x01)
  17. OUT_TXD_H();
  18. else
  19. OUT_TXD_L();
  20. NewTxData >>= 1;
  21. nCountTxData ++;
  22. }
  23. }
  24. ExitCritical(&r);
  25. }

接收部分

原理

GPG0 收到下降沿信号(起始位,代表对方开始发送),启动接收定时器

接收定时器(Timer3)周期为波特率对应信号周期的一半

在第3,5,7,9,11,13,15,17次定时器触发时取值,可避开起始位(第一次触发)和边沿信号(偶数次)

接收定时器初始化部分

  1. //timer3 接收时钟 接收管脚 GPH3
  2. void VirUart_Rx_TimerInit(int baud)
  3. {
  4. int time_cnt;
  5. // int time_Prescaler1 = 0; // 预分频
  6. //int samples = 10; // 采样数
  7. // 计算计数常数
  8. time_cnt = PCLK / (1 * 2) / (baud * 2);
  9. // 设置定时器配置寄存器0
  10. rTCFG0 = 0; // 预分频数值 为 0
  11. // 设置定时器配置寄存器1
  12. rTCFG1 = 0; // 分割器值 为 0 1/2PLCK
  13. // 设置计数器
  14. rTCNTB3 = time_cnt;
  15. // 设置控制寄存器
  16. rTCON = (rTCON & (~(0x1f << 16))) | (0x02 << 16); // 更新 TCNTB2
  17. rTCON = (rTCON & (~(0x1f << 16))) | (0x09 << 16); // 设置Timer2 自动加载 并启动
  18. // rINTPND |=BIT_TIMER3; // 清零
  19. rINTPND = rINTPND; // 清零
  20. rINTMSK &= ~BIT_TIMER3; // 打开 Timer2 中断
  21. pISR_TIMER3 = (U32)Time3_Rx_Ir;
  22. }

EINT8中断处理程序

EINT8 中断代表GPG0,GPH3 收到下降沿,开始读取工作

  1. void __irq VirUart_RX_ISR(void)
  2. {
  3. VirUart_Rx_TimerInit(); //启动接收定时器
  4. RxData = 0; // 清空数据
  5. nCountRxData = 0;
  6. Timer3_Tick = 0; // Timer3 Tick 数清零
  7. }

Timer3 中断服务程序

Timer3 在 Timer3_Tick = 3,5,7,9...时接收数据
下面代码完成了数据的接收

  1. void __irq Time3_Rx_Ir(void)
  2. {
  3. U32 r;
  4. EnterCritical(&r);
  5. if (rINTPND == BIT_TIMER2)
  6. {
  7. ClearPending(BIT_TIMER2);
  8. Timer3_Tick ++;
  9. if (Timer3_Tick >= 3 && (Timer3_Tick & 0x1)) // 在Tick 3,5,7,9....时接收数据
  10. {
  11. if(nCountRxData>=data_width + (parity_check > 1)) // 接收完成
  12. {
  13. //flagRx = 3;
  14. rINTMSK |= BIT_TIMER3; // 关闭 Timer3 中断
  15. rTCON = (rTCON &(~(0x1f<<16))); //关闭 TCNTB3
  16. NewRxData = RxData & (1 << data_width); // 接收数据并不需要校验位
  17. NewFlagRx = 1; //指示接收数据完成
  18. }
  19. else
  20. {
  21. if (GET_RXD_PIN()&0x01)
  22. {
  23. RxData=RxData | (1 << (data_width + (parity_check > 1)));
  24. }
  25. RxData >>=1;
  26. nCountRxData ++;
  27. }
  28. }
  29. }
  30. ExitCritical(&r);
  31. }

主程序(main.c)

本程序实现RS323 Echo 功能,即在RX(GPH3)接收到的字符直接经TX(GPH2)经RS232发回.
下面列出main函数主要部分

  1. VirUsart_init(19200, 8, 1, 0); //19200bps,8位数据,1位停止位,无校验
  2. while (1)
  3. {
  4. if (NewFlagRx)
  5. {
  6. NewTxData = NewRxData; //将接收到的数据存储
  7. NewFlagRx = 0; // 设置接收未处理标志位0
  8. NewFlagTx = 1; // 设置未发送标志
  9. VirUartTxData_task(); // 发送字符
  10. }
  11. }

VirUart.h

提供了虚拟串口程序的接口定义

  1. void VirUartTxData_task(void);
  2. void VirUsart_init(int _baud, int _data_width, int _stop_bit, int _parity_check);
  3. extern volatile unsigned char NewFlagTx ;
  4. extern volatile unsigned short NewTxData ;
  5. extern volatile unsigned char NewFlagRx ;
  6. extern volatile unsigned short NewRxData ;
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注