📄 simulatecomm - 调试成功.cpp
字号:
#include <stdio.h>
#include <string.h>
#include "..\LIB\ArmOS\ArmLib.h"
#include "..\LIB\ArmOS\ArmOs.h"
#include "HdrIntfc.h"
#include "SimulateComm.h"
/*-------------------------------------------------------------------------------------------------------------
模拟串口说明
占用资源:
1. RCV_CAP , 用于接收:直接连接到某个引脚,用来接收。检测起始位时配置为下降沿触发,以后配置为跳变触发。
如果两次触发的间隔小于1bit时间,则设置错误标志
2. RCV_MAT , 用于接收:检测到起始位后定时到一个字节时间(1个起始位,8数据位,1校验位,1或者2停止位)
3. SND_MAT , 用于发送:每个bit时间发生出一个bit。
使用本模块前,必须先设置好引脚的模式:TX在 MATCH 模式,而RX 在 capture 模式
-------------------------------------------------------------------------------------------------------------*/
//-------------------------------------------------------------------------------------------------------------
// 用户定义:数据位、校验位、波特率、硬件时钟、引脚
//-------------------------------------------------------------------------------------------------------------
#define SU_BAUD_RATE 9600
#define SU_DATA_BIT_COUNT 8
#define SU_PARITY_MODE 0 //0-NONE, 1-ODD, 2-EVEN全0填0, 3-MARK总填1, 4-SPACE填0
#define SU_STOP_BIT_COUNT 1
//缓冲区定义
#ifndef SU_XMIT_SIZE
#define SU_XMIT_SIZE 128
#endif
#ifndef SU_RCV_SIZE
#define SU_RCV_SIZE 128
#endif
#define SIMU_COMM_TIMER 0
//SIMULATED UART, RECEIVE CAPTURE INDEX
#define SU_RCV_CAP 2
//SIMULATED UART, RECEIVE MATCH INDEX
#define SU_RCV_MAT 1
//SIMULATED UART, SEND MATCH INDEX
#define SU_SND_MAT 2
//SIMULATED UART, RECIEVE PIN PORT NUMBER
#define SU_RCV_PIN_X 0
//SIMULATED UART, RECIEVE PIN NUMBER
#define SU_RCV_PIN 16
//-------------------------------------------------------------------------------------------------------------
// 使用用户定义生成对时钟的访问宏
//-------------------------------------------------------------------------------------------------------------
#if SIMU_COMM_TIMER == 0
#define ISN_TIMERX ISN_TIMER0
#define TX_SOFT_INT_FLAG 0X10
#define TXPR T0PR
#define TXTCR T0TCR
#define TXCCR T0CCR
#define TXMCR T0MCR
#define TXTC T0TC
#define TXIR T0IR
#define TXEMR T0EMR
#define TXMR (&T0MR0)
#define TXCR (&T0CR0)
#elif SIMU_COMM_TIMER == 1
#define ISN_TIMERX ISN_TIMER1
#define TX_SOFT_INT_FLAG 0X20
#define TXPR T1PR
#define TXTCR T1TCR
#define TXCCR T1CCR
#define TXMCR T1MCR
#define TXTC T1TC
#define TXIR T1IR
#define TXEMR T1EMR
#define TXMR (&T1MR0)
#define TXCR (&T1CR0)
#else
#error "Simulate UART timer definition missing"
#endif
#if SU_PARITY_MODE == 0
#define SU_PARITY_BIT_COUNT 0
#else
#define SU_PARITY_BIT_COUNT 1
#endif
#define RCV_CAP_TM TXCR[SU_RCV_CAP]
#define RCV_MAT_TM TXMR[SU_RCV_MAT]
#define SND_MAT_TM TXMR[SU_SND_MAT]
//-------------------------------------------------------------------------------------------------------------
// 模拟串口有关时间的定义
//-------------------------------------------------------------------------------------------------------------
//Fpclk = 2764800
#define FREQ_T0 (Fpclk/9)
//#define PULSE_WIDTH Fpclk / 19200 //052us, FOR 19200 bps
#define PULSE_WIDTH Fpclk /(SU_BAUD_RATE) /9 //104us, FOR 9600 bps
//#define PULSE_WIDTH Fpclk / 833 //833us, FOR 1200 bps
#define PULSE_WIDTH_FIRST (PULSE_WIDTH + PULSE_WIDTH / 2)
//-------------------------------------------------------------------------------------------------------------
// 模拟串口接收
//-------------------------------------------------------------------------------------------------------------
class CSimuRcv
{
static unsigned char simu_rcv_buf[SU_RCV_SIZE];
enum{RS_WAITING_START, RS_RECEIVING_BITS };
static uint8 rcv_state ;
static uint8 bit_pos ;
static bool bit_value ;
static uint32 bit_flag ;
static uint32 rcv_value;
static uint32 last_bit_time ;
//禁止捕获,用于收到非法脉冲时
static void EnableCaptureFallAndRise()
{
TXCCR |= (7 << (SU_RCV_CAP * 3));
}
static void EnableCaptureFall()
{
TXCCR = (TXCCR & ~(7 << (SU_RCV_CAP * 3))) | (6 << (SU_RCV_CAP * 3));
}
//允许捕获,用户当前非法脉冲过去后
static void DisableCapture()
{
TXCCR &= ~(7 << (SU_RCV_CAP * 3));
TXIR = CAP_ISR(SU_RCV_CAP);
}
//设置比较时间,就是当前要接收的字节结束的时间
static void SetMatchTime(uint32 time)
{
RCV_MAT_TM = time;
TXMCR = (TXMCR & ~(7 << (SU_RCV_MAT*3))) | (1 << (SU_RCV_MAT*3));
}
static void ClearMatchIsr()
{
TXMCR = (TXMCR & ~(7 << (SU_RCV_MAT*3)));
TXIR = MATCH_ISR(SU_RCV_MAT);
}
static void OnCapture(uint32 captured_time, bool pin_changed)
{
switch(rcv_state)
{
case RS_WAITING_START:
//仅仅在下降沿才会启动接收
if(GetPinState(SU_RCV_PIN_X, SU_RCV_PIN) == 0)
{
EnableCaptureFallAndRise();
rcv_state = RS_RECEIVING_BITS;
bit_pos = 0;
bit_value = 0;
bit_flag = 1;
rcv_value = 0;
last_bit_time = captured_time;
//字节结束时间:1起始位,数据位,校验位。停止位不要包括,因为它总是1
SetMatchTime(captured_time + (1 + SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT) * PULSE_WIDTH);
}
break;
case RS_RECEIVING_BITS:
//检查接收错误
if(captured_time - last_bit_time < PULSE_WIDTH * 3 / 4)
{
//错误处理有一个目的:如果RX引脚有干扰,那么频繁的中断可能导致CPU总是忙于该中断
//因此如果检测到错误就放弃接收,等待从定时器中恢复
DisableCapture();
}else
{
while((last_bit_time + PULSE_WIDTH / 2 < captured_time && bit_pos < SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT))
{
if(pin_changed && last_bit_time + PULSE_WIDTH * 3 / 2 > captured_time)
bit_value = ! bit_value;
if(bit_value)
rcv_value |= bit_flag;
bit_pos ++;
bit_flag <<= 1;
last_bit_time += PULSE_WIDTH;
}
//如果接收了足够的bit,添加到接收队列
if( bit_pos >= SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
{
qRcv.Add(rcv_value);
rcv_state = RS_WAITING_START;
EnableCaptureFall();
TXIR = CAP_ISR(SU_RCV_CAP); //清除可能的捕获中断
ClearMatchIsr(); //因为已经接收完成,因此定时器也清除
}
}
break;
default:
rcv_state = RS_WAITING_START;
break;
}
}
public:
static class CQueue qRcv;
static void Init(void)
{
rcv_state = RS_WAITING_START;
EnableCaptureFall();
}
static void OnRxCapture()
{
OnCapture(RCV_CAP_TM, true);
}
static void OnByteTimerExpires()
{
OnCapture(RCV_MAT_TM, false);
rcv_state = RS_WAITING_START;
EnableCaptureFall();
ClearMatchIsr(); //因为已经接收完成,因此定时器也清除
}
};
unsigned char CSimuRcv::simu_rcv_buf[SU_RCV_SIZE];
class CQueue CSimuRcv::qRcv(simu_rcv_buf,SU_RCV_SIZE) ;
uint8 CSimuRcv::rcv_state ;
uint8 CSimuRcv::bit_pos ;
bool CSimuRcv::bit_value ;
uint32 CSimuRcv::bit_flag ;
uint32 CSimuRcv::rcv_value;
uint32 CSimuRcv::last_bit_time ;
//-------------------------------------------------------------------------------------------------------------
// 模拟串口发送
//-------------------------------------------------------------------------------------------------------------
class CSimuSend
{
static unsigned char buf[SU_XMIT_SIZE];
static volatile uint8 is_sending, is_end_of_send;
static uint8 bit_pos ;
static bool bit_value ;
static uint32 bit_flag ;
static uint32 send_value, last_bit_time;
static class CQueue qSend;
static void SetTimerWithTogglePin(uint32 time)
{
TXEMR |= 3 << (4 + SU_SND_MAT * 2); //比较成功时的引脚反转
SND_MAT_TM = time;
TXMCR |= 1 << (SU_SND_MAT * 3); //比较成功时触发中断
}
static void SetTimerWithSetPin(uint32 time)
{
TXEMR = (TXEMR & ~(3 << (4 + SU_SND_MAT * 2))) | (2 << (4 + SU_SND_MAT * 2)); //比较成功时的引脚置位
SND_MAT_TM = time;
TXMCR |= 1 << (SU_SND_MAT * 3); //比较成功时触发中断
}
/* static void SetTimer(uint32 time)
{
TXEMR &= ~(3 << (4 + SU_SND_MAT * 2)); //不控制引脚引脚
SND_MAT_TM = time;
TXMCR |= 1 << (SU_SND_MAT * 3); //比较成功时触发中断
}*/
static void ClearTimer()
{
TXEMR &= ~(3 << (4 + SU_SND_MAT * 2)); //不控制引脚引脚
TXMCR &= ~(7 << (SU_SND_MAT * 3)); //不触发中断
}
static void SetTxPin()
{
TXEMR |= 1 << SU_SND_MAT;
}
static void ClearTxPin()
{
TXEMR &= ~(1 << SU_SND_MAT);
}
//发送之前先把 parity 放在 send_value 的第8bit(0-7bit是数据位)
static void SendByte()
{
//如果刚开始发送,则先把TX引脚拉低
if(bit_pos == 0)
{
bit_value = 0;
bit_flag = 1;
ClearTxPin();
last_bit_time = TXTC;
}
//如果发送结束,则发送停止位
if(bit_pos >= 1+SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
{
SetTimerWithSetPin(last_bit_time + SU_STOP_BIT_COUNT * PULSE_WIDTH);
is_sending = false;
bit_pos = 0;
//发送数据位和校奇偶校验
}else
{
bool found =false;
while(! found && bit_pos < 1+SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
{
if(bit_value != ((bit_flag & send_value) != 0))
{
bit_value = !bit_value;
found = true;
}
last_bit_time += PULSE_WIDTH;
bit_pos ++;
bit_flag <<= 1;
}
if(bit_pos >= 1+SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
{
SetTimerWithSetPin(last_bit_time); //最终到停止位,那么就把引脚置位
}else
{
SetTimerWithTogglePin(last_bit_time); //需要反转引脚
}
}
}
static void FillParityBit()
{
uint8 parity = SU_PARITY_MODE;
if(parity == 0)
return;
uint32 bit_count, flag;
switch(parity)
{
case 0:
break;
case 1:
case 2:
bit_count = 0;
flag = 1;
for(int i=0;i<SU_DATA_BIT_COUNT;i++, flag <<= 1)
{
if(send_value & flag)
bit_count = !bit_count;
}
if(bit_count == (SU_PARITY_MODE == 2))
send_value |= (1<<SU_DATA_BIT_COUNT);
break;
case 3: //mark
send_value |= (1<<SU_DATA_BIT_COUNT);
break;
case 4: //space
break;
}
}
static void StartSend()
{
soft_start_send = true;
VICSoftInt |= TX_SOFT_INT_FLAG;
}
public:
static bool soft_start_send;
static bool IsEndOfSend() { return is_end_of_send;};
static void OnSendBit()
{
//SetSysLed(2); 调试点,看中断时间
is_end_of_send = false;
if(is_sending)
{
SendByte();//如果发送完毕,将清除is_sending 标志
}else if( ! qSend.IsEmpty())
{
send_value = qSend.Get();
FillParityBit();
SendByte();
is_sending = true;
}else
{
ClearTimer();
is_end_of_send = true;
}
}
static void PutCh(char c)
{
qSend.Add(c);
if(IsEndOfSend())
{
StartSend();
}
}
static void Init()
{
SetTxPin();
bit_pos = 0;
is_end_of_send = true;
}
};
unsigned char CSimuSend::buf[SU_XMIT_SIZE];
volatile uint8 CSimuSend::is_sending;
volatile uint8 CSimuSend::is_end_of_send;
uint8 CSimuSend::bit_pos ;
bool CSimuSend::bit_value ;
bool CSimuSend::soft_start_send ;
uint32 CSimuSend::bit_flag ;
uint32 CSimuSend::send_value, CSimuSend::last_bit_time;
class CQueue CSimuSend::qSend(buf, sizeof(buf));
//-------------------------------------------------------------------------------------------------------------
// 模拟串口中断入口
//-------------------------------------------------------------------------------------------------------------
//返回发生的中断bit,将被写入 T0IR
//该函数将被多次调用,直到没有中断。
uint8 IsrEntry_ForSimmuComm()
{
uint8 clear_flag = 0;
//RXD 捕获
if(TXIR & CAP_ISR(SU_RCV_CAP))
{
clear_flag |= CAP_ISR(SU_RCV_CAP);
CSimuRcv::OnRxCapture();
}
//RXD 匹配
if(TXIR & MATCH_ISR(SU_RCV_MAT))
{
clear_flag |= MATCH_ISR(SU_RCV_MAT);
CSimuRcv::OnByteTimerExpires();
}
//TXD 匹配
if((TXIR & MATCH_ISR(SU_SND_MAT)) || CSimuSend::soft_start_send)
{
if(CSimuSend::soft_start_send)
{
CSimuSend::soft_start_send = false;
VICSoftIntClear |= TX_SOFT_INT_FLAG;
}
CSimuSend::OnSendBit();
clear_flag |= MATCH_ISR(SU_SND_MAT);
}
return clear_flag;
}
//如果使用了T0的其它中断功能,则在此判断
uint8 OSIsrHook()
{
SetSysLed(1);
TXIR = IsrEntry_ForSimmuComm();
SetSysLed(0);
return 0;
}
/*
void _________task2________()
*/
#include "..\LIB\ArmOS\OSObject.h"
class CTask2 : public CAbsTask
{
uint32 stack[100]; //0
virtual void GetTaskInfo(uint32 *&stack_ptr, int &stack_size, int &task_id)
{
stack_ptr = stack;
stack_size = sizeof(stack);
task_id = TASK_ID_TEST;
}
virtual int Execute();
} task2;
int CTask2::Execute()
{
SetSysLed(0);
CSimuRcv::Init();
CSimuSend::Init();
while(1)
{
OSWDTReset();
Sleep(100);
// CSimuSend::PutCh(0xff);
while(! CSimuRcv::qRcv.IsEmpty())
{
char c = CSimuRcv::qRcv.Get();
// printf("%c",c);
CSimuSend::PutCh(c);
}
while(! uart0_rcv_queue.IsEmpty())
{
char c = uart0_rcv_queue.Get();
// printf("%c",c);
CSimuSend::PutCh(c);
}
//CSimuSend::SetTimerWithTogglePin(TXTC + 50);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -