S32K312 IO模拟串口UART接收数据

工程中S32K312的8个串口资源均已使用,需要使用一个IO来模拟串口UART接收数据。

IO模拟串口接收数据,首先需要了解串口的理论知识。

一帧数据从下降沿的起始位开始,上升沿的停止位结束。起始位后有8个bit的数据位,数据位低位(bit0)先传,数据位高位(bit7)后传,数据位后跟着奇偶校验位。校验位:用于确保传输数据的正确性,可分为奇校验和偶校验。奇校验时数据位和校验位中1的总数应为奇数;同理,偶校验时数据位和校验位中1的总数应为偶数。

波特率单位bps的含义是bit/s,本文以19200bps波特率为例,每个bit持续的时间约为52us

实现IO模拟串口接收,需要能够检测IO上升沿中断和52us级别的定时器。

在S32K312芯片上实现IO模拟串口接收,我使用Siul2_Icu的IO中断和PIT定时器结合的方式来实现。

IO中断检测参考博文《S32K312 IO中断(Siul2_Icu)

代码实现思路

1)IO上升沿触发中断,在中断函数中延时26us,开启52us的定时器;

2)进入定时器中断函数9次,读取IO的电平值,关闭定时器,开启IO上升沿中断功能。第9次校验数值是否正确。

参考代码

main.c

/* Including necessary configuration files. */
#include "Mcal.h"
#include "Pit_Ip.h"
#include "Clock_Ip.h"
#include "IntCtrl_Ip.h"
#include "Siul2_Icu_Ip.h"
#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"

volatile int exit_code = 0;
/* User includes */
#include "SEGGER_RTT_Conf.h"
#include "SEGGER_RTT.h"
#include "uart_io_imitate.h"
#include <string.h>

void my_delay_us(unsigned int delay_time)
{
    uint32_t DelayTimer = 0;
    uint32_t cnt = delay_time * 32;
    while (DelayTimer++ < cnt);
}

uint8_t LOG_Data[256];
void LOG_INFO_Buffer(uint8_t *pData,uint16_t length)
{
	uint16_t i = 0;
	uint8_t value = 0;
	memset(LOG_Data, 0, 256);
	for(i=0;i<length && i<(256/3);i++)
	{
		value =  (((*(pData+i))&0xF0) >> 4);
		LOG_Data[i*3 +0] = (value <= 9)? value +'0' : value -10 + 'A';
		value =  ((*(pData+i))&0x0F);
		LOG_Data[i*3 +1] = (value <= 9)? value +'0' : value -10 + 'A';
		LOG_Data[i*3 +2] = ' ';
	}
	SEGGER_RTT_printf(0, "%s\n", LOG_Data);
}

/*!
  \brief The main function for the project.
  \details The startup initialization sequence is the following:
 * - startup asm routine
 * - main()
*/
uint8_t buff[128];
uint8_t len;
int main(void)
{
    /* Write your code here */
	SEGGER_RTT_printf(0,"main start\n");
	/* Initial Clock */
	Clock_Ip_Init(&Clock_Ip_aClockConfig[0]);
	/*Initial Pin */
	Siul2_Port_Ip_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);
	/*Initial ISR*/
	IntCtrl_Ip_Init(&IntCtrlConfig_0);
	IntCtrl_Ip_ConfigIrqRouting(&intRouteConfig);

	bsp_init_io_imitate_uart();


    for(;;)
    {
    	if(bsp_io_imitate_uart_get_recv_datas(buff, &len) == 0)
    	{
    		SEGGER_RTT_printf(0,"len=%d\n", len);
    		LOG_INFO_Buffer(buff, len);
    	}
    	my_delay_us(100*1000);
        if(exit_code != 0)
        {
            break;
        }
    }
    return exit_code;
}

uart_io_imitate.c文件参考(IO引脚是PTB9)

#include "uart_io_imitate.h"

#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "Pit_Ip.h"
#include "IntCtrl_Ip.h"
#include "Siul2_Icu_Ip.h"
#include <string.h>

#include "SEGGER_RTT_Conf.h"
#include "SEGGER_RTT.h"

/* PIT instance used - 0 */
#define PIT_INST_0 0U
/* PIT Channel used - 0 */
#define CH_0 0U
/* PIT time-out period - equivalent to 1s */
#define PIT_PERIOD 2080//52us
//#define PIT_PERIOD 2000//50us
//#define PIT_PERIOD 40000//1ms
//#define PIT_PERIOD 400000//10ms
//#define PIT_PERIOD 40000000//1s

typedef struct _IO_IMITATE_UART_
{
	uint8_t recv_byte;
	uint8_t int_cnt;
	uint8_t cs_code;
	uint16_t idle_check;
	uint8_t frame_ok;
	uint8_t recv_datas[128];
	uint8_t recv_len;
} IO_IMITATE_UART;

IO_IMITATE_UART io_imitate_uart = {0, };

static void delay_us(unsigned int delay_time)
{
    uint32_t DelayTimer = 0;
    uint32_t cnt = delay_time * 32;
    while (DelayTimer++ < cnt);
}

void bsp_io_imitate_uart_disable_edge_detect(void)
{
	IntCtrl_Ip_DisableIrq(SIUL_1_IRQn);
	Siul2_Icu_Ip_DisableInterrupt(0, 15);
	Siul2_Icu_Ip_EnableNotification(0, 15);
}

void bsp_io_imitate_uart_enable_edge_detect(void)
{
	IntCtrl_Ip_EnableIrq(SIUL_1_IRQn);
	Siul2_Icu_Ip_EnableInterrupt(0, 15);
	Siul2_Icu_Ip_EnableNotification(0, 15);
}

void bsp_io_imitate_uart_disable_pitimer(void)
{
	Pit_Ip_StopChannel(PIT_INST_0, CH_0);
	Pit_Ip_DisableChannelInterrupt(PIT_INST_0, CH_0);
}

void bsp_io_imitate_uart_enable_pitimer(void)
{
	Pit_Ip_EnableChannelInterrupt(PIT_INST_0, CH_0);
	Pit_Ip_StartChannel(PIT_INST_0, CH_0, PIT_PERIOD);
}

static uint8_t bsp_even_parity_check(uint8_t data, uint8_t code)
{
	uint8_t i, tmpcode = 0;
	for(i = 0; i < 8; i++)
	{
		tmpcode += ((data >> i) & 0x01);
	}
	tmpcode += code;
	if(tmpcode % 2 == 0)
	{
		return 0;
	}
	return 1;
}

static uint8_t get_ptb9_lev(void)
{
	return Siul2_Dio_Ip_ReadPin(PTB_L_HALF, 9);
}

void bsp_init_io_imitate_uart(void)
{
	/*Initial PIT instance 0 - Channel 0*/
	Pit_Ip_Init(PIT_INST_0, &PIT_0_InitConfig_PB);
	/*Initial channel 0 */
	Pit_Ip_InitChannel(PIT_INST_0, PIT_0_CH_0);
	/*Enable channel interrupt PIT_0 - CH_0*/
	Pit_Ip_EnableChannelInterrupt(PIT_INST_0, CH_0);
	/*Start channel CH_0*/
//	Pit_Ip_StartChannel(PIT_INST_0, CH_0, PIT_PERIOD);

	IntCtrl_Ip_InstallHandler(SIUL_1_IRQn, &SIUL2_EXT_IRQ_8_15_ISR, NULL_PTR);
	IntCtrl_Ip_EnableIrq(SIUL_1_IRQn);

	/* Initialize the Icu driver */
	Siul2_Icu_Ip_Init(0, &Siul2_Icu_Ip_0_Config_PB_BOARD_InitPeripherals);

	Siul2_Icu_Ip_EnableInterrupt(0, 15);
	Siul2_Icu_Ip_EnableNotification(0, 15);
}

//uint32_t UserCountIrqCH0 = 0;
void User_EdgeDetect0(void)
{
//	SEGGER_RTT_printf(0,"User_EdgeDetect0 io_imitate_uart.int_cnt = %d\n", io_imitate_uart.int_cnt);
	bsp_io_imitate_uart_disable_edge_detect();
	bsp_io_imitate_uart_disable_pitimer();
	delay_us(16);
	if(Siul2_Dio_Ip_ReadPin(PTB_L_HALF, 9) == LEV_LOW)
	{
		SEGGER_RTT_printf(0,"Siul2_Dio_Ip_ReadPin LEV_LOW!!!!!!!\n");
		bsp_io_imitate_uart_enable_edge_detect();
		return;
	}
	bsp_io_imitate_uart_enable_pitimer();
	io_imitate_uart.int_cnt = 0;
	io_imitate_uart.recv_byte = 0;
}

//uint32_t pitIrq = 0;
uint8_t ptb9_lev;
void pitNotification(void)
{
//	Siul2_Dio_Ip_TogglePins(PTB_L_HALF, 1 << 12);
//	SEGGER_RTT_printf(0,"program interrupt pitIrq = %d\n", pitIrq++);
	if(io_imitate_uart.int_cnt < 8)
	{
		io_imitate_uart.recv_byte |= (get_ptb9_lev() << io_imitate_uart.int_cnt);
//		io_imitate_uart.recv_byte |= (get_ptb9_lev() << (7 - io_imitate_uart.int_cnt));
	}
	else if(io_imitate_uart.int_cnt == 8)
	{
		bsp_io_imitate_uart_disable_pitimer();
		bsp_io_imitate_uart_enable_edge_detect();
		io_imitate_uart.cs_code = get_ptb9_lev();
		SEGGER_RTT_printf(0,"io_imitate_uart.int_cnt = 8, recv_byte = 0X%02X, cs_code = 0X%02X\n", io_imitate_uart.recv_byte, io_imitate_uart.cs_code);
		if(bsp_even_parity_check(io_imitate_uart.recv_byte, io_imitate_uart.cs_code) == 0)
		{
			if(io_imitate_uart.recv_len < sizeof(io_imitate_uart.recv_datas))
			{
				io_imitate_uart.recv_datas[io_imitate_uart.recv_len] = io_imitate_uart.recv_byte;
				io_imitate_uart.recv_len++;
			}
		}
		else
		{
			SEGGER_RTT_printf(0,"bsp_even_parity_check() failed\n");
		}
	}
	io_imitate_uart.int_cnt++;
}

uint8_t bsp_io_imitate_uart_get_recv_datas(uint8_t* datas, uint8_t* len)
{
	if(io_imitate_uart.recv_len > 0)
	{
		memcpy(datas, &io_imitate_uart.recv_datas[0], io_imitate_uart.recv_len);
		*len = io_imitate_uart.recv_len;
		io_imitate_uart.recv_len = 0;
		return 0;
	}
	return 1;
}

最终接收串口数据的效果

外部中断模拟串口,波特率不能超过65536 实验测试:发送57600可以正常,但接收只能 <= 38400 #include "Uart_EXT0.h" #include "MAIN.h" #define FOCS 22114800ul bit Over; bit bRxflag; unsigned char IEN0_NOW,IEN1_NOW; //中断临时变量 unsigned char idata bRxstate=0; //接收状态 unsigned char idata tmp_Len=0; //缓存数组下标 unsigned char idata bRxlen; //接收字节数 unsigned char xdata EX_buf[64]; //接收存放区 /*************************************************** baud = 56000 接收一字节 =178.6us ,接收会出现错误 baud = 38400 接收一字节 =260.4us //快速接收都容易出现错误 baud = 19200 接收一字节 =520us | baud = 14400 接收一字节 =694.5us | baud = 9600 接收一字节 =1041.6us | baud = 4800 接收一字节 =2.083ms 接收过长,定时器MODE2无法满足 //主机发送的数据最好加上校验字 发送:最大57600,发送还能正常。 ****************************************************/ void Time0_Uart(unsigned int baud) { TMOD &= 0XF0; TMOD |= 0X02; //使用定时器0方式2,使用方式1则2400波特也能有 TH0 = 256-(FOCS/12)/baud; TL0 = TH0; IP0 |= 0x02; //设置为最高优先级 IP1 |= 0x02; TR0 = 1; ET0 = 1; EA = 1; } void Time0_isr() interrupt 1 { //方式1则重装值 Over = 1; } /* 发送数据,1起始位,8数据,1停止位 发送波特率实验57600都不会错误,大量发送数据待测试 */ void Uart_set(unsigned char dat) { unsigned char i; Over = 0; TL0 = TH0; //防止发送数据开始时不知道TL0是多少 T_uart = 0; //起始位 while(Over==0); Over = 0; for(i=0;i>= 1; } // Over = 0; //数据位清零了 T_uart = 1; //停止位,此后如果没有数据则一直为高 while(Over==0); } unsigned char get_Uart() { unsigned char I=0,get_dat=0; Over = 0; TL0 = TH0; //重新赋值,防止出错 while(Over==0); Over = 0; for(I=0;I>= 1; if(Get_ex == 1) get_dat |= 0x80; else get_dat &= 0x7f; while(Over==0); Over = 0; } if(Get_ex == 1) { Over = 0; } return get_dat; } void EXuart_isr() interrupt 0 { unsigned char _chr; IEN0_NOW = IEN0; //进入接收1字节,关闭中断 IEN1_NOW = IEN1; IEN0 = 0X82; IEN1 = 0; _chr=get_Uart(); switch(bRxstate) { case 0: if(_chr==0x55) { bRxstate=1; } else bRxstate=0; break; case 1: if(_chr==0xaa) { bRxstate=2; } else bRxstate=0; break; case 2: //取得数据长度 bRxlen=_chr; bRxstate=3; break; case 3: EX_buf[tmp_Len]=_chr; tmp_Len++; if(tmp_Len==bRxlen) { bRxstate=0; tmp_Len=0; bRxflag=1; //一帧数据接收完毕,置位完成标志位 } break; default: break; } IE0 = 0; //清外部0中断标志,防止下次接收不到 IEN0 = IEN0_NOW; IEN1 = IEN1_NOW; } void main() { Time0_Uart(9600); EX_uart(); if(bRxflag==1) { bRxflag = 0; for(i=0;i<10;i++) RevBuffer[i] = EX_buf[i]; T0Uart_TX(10,RevBuffer); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值