工程中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;
}
最终接收串口数据的效果