目录一、UART工作原理1.帧格式编辑.奇偶校验位.FIFO、DATA 数据寄存器、移位寄存器完整数据流.开启FIFO.关闭FIFO.通讯过程二、S32K44 UART通讯1.主要寄存器说明BAUDCTRLSTATDATA2.三种通讯方式2.1.使用DATA寄存器未使用FIFO通讯clock.cuart.cuart.hmain.cio.c2.2.使用DATA寄存器且使用FIFO通讯2.3.使用FIFO轮询通讯一、UART工作原理UART是一种通用串行数据总线用于异步通信。该总线双向通信可以实现全双工传输和接收⑴输出缓冲寄存器它接收CPU从数据总线上送来的并行数据并加以保存。uart基本结构⑵ 输出移位寄存器它接收从输出缓冲器送来的并行数据以发送时钟的速率把数据逐位移出即将并行数据转换为串行数据输出。⑶ 输入移位寄存器它以接收时钟的速率把出现在串行数据输入线上的数据逐位移入当数据装满后并行送往输入缓冲寄存器即将串行数据转换成并行数据。⑷ 输入缓冲寄存器它从输入移位寄存器中接收并行数据然后由CPU取走。⑸控制寄存器它接收CPU送来的控制字由控制字的内容决定通信时的传输方式以及数据格式等。例如采用异步方式还是同步方式数据字符的位数有无奇偶校验是奇校验还是偶校验停止位的位数等参数。⑹状态寄存器。状态寄存器中存放着接口的各种状态信息例如输出缓冲区是否空输入字符是否准备好等。在通信过程中当符合某种状态时接口中的状态检测逻辑将状态寄存器的相应位置1以便让CPU查询。1.帧格式起始位当有数据要发送时数据信号线变成低电平并持续一段时间用于表示字符的开始这一位称为起始位。数据位紧接着起始位之后。在信号线上会依次出现待发送的每一位字符最低有效位D0最先出现因此它最早被发送出去。采用不同的编码方案数据位的个数不同数据位的个数可以是4、5、6、7、8等当字符用ASCII码表示时数据位占7位D0~D7。奇偶校验位数据位加上这一位后使得“1”的位数应为偶数(偶校验)或奇数(奇校验)以此来校验资料传送的正确性例如数据传输采用奇校验时如果数据“1”的个数是奇数这一位就被置为“0”反之置为“1”。当然系统中也可以不采用奇偶校验。停止位它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的并且每一个设备有其自己的时钟很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束并且提供计算机校正时钟同步的机会。适用于停止位的位数越多不同时钟同步的容忍程度越大但是数据传输率同时也越慢。奇偶校验位的后面至少应该有一位高电平表示停止位如果传输完一个字符后立即传输下一个字符那么后一个字符的起始位就紧跟着前一个字符的停止位否则停止位后又进入一个空闲状态。空闲位处于逻辑“1”状态表示当前线路上没有数据传送。.奇偶校验位在异步串行通信中如何知道一个字节的传输是否正确的最常见的方法是增加一个位奇偶校验位供错误检测使用。字符奇偶校验检查Character Parity CheckingCPC也称为垂直冗余检查Vertical Redundancy CheckingVRC它为每个字节增加一个额外位使字节中 1 的个数为奇数或偶数奇数或偶数依据使用的是奇校验检查还是偶校验检查而定。当使用奇校验检查时如果字节数据位中 1 的数目是偶数校验位应为 1如果 1 的数目是奇数校验位应为 0当使用偶校验检查时如果字符数据位中 1 的数目是偶数则校验位应为 0否则为 1。这里列举奇偶校验检查的一个实例如 ASCII 字符 R其二进制数为 1010010。由于字符 R 中有 3 个位为 1若使用奇校验检查则校验位为 0若使用偶校验检查则校验位为 1。在传输过程中若有 1 位或奇数个数据位发生错误使用奇偶校验检查可以知道发生传输错误若有 2 位或偶数个数据位发生错误使用奇偶校验检查就不能知道已经发生了传输错误。但是奇偶校验检查方法简单使用方便发生 1 位错误的概率远大于 2 位的概率所以奇偶校验这种方法还是最为常用的校验方法。几乎所有 MCU 的串行异步通信接口都提供这种功能。但实际编程使用较少原因是单字节校验意义不大。.FIFO、DATA 数据寄存器、移位寄存器完整数据流DATA 寄存器TDR 发送 / RDR 接收软件唯一交互入口CPU 通过 APB 总线读写只有这个寄存器有内存地址代码直接操作发送 / 接收共用同一寄存器地址硬件内部物理分离。硬件 FIFOTX_FIFO/RX_FIFO可选缓存队列多字节硬件缓冲区常见 8/16/32 字节DATA ↔ 移位寄存器中间缓冲层无 FIFO 时直接 DATA↔移位寄存器。移位寄存器Tx Shift Reg / Rx Shift Reg底层串行转换单元无软件地址硬件私有负责并行字节 ↔ 串行比特流转换逐位输出 / 采样 TX/RX 引脚。.开启FIFO发送CPU 写 TDR (DATA) → TX_FIFO → Tx 移位寄存器 → TX 引脚串行输出CPU 轮询 / 中断判断 TXFIFO 未满执行代码写入字节到TDRDATA 发送寄存器硬件自动把 TDR 内数据移入TX_FIFO立刻释放 TDRCPU 可继续写下一字节TX_FIFO 非空时硬件持续从 FIFO 头部取出 1 字节送入Tx 移位寄存器移位寄存器按波特率时钟逐比特输出起始位 数据位 校验 停止位到 TX 引脚单字节发完后移位寄存器清空若 TX_FIFO 仍有数据自动重复步骤 3 继续发送触发条件TX_FIFO 达到空阈值时置 TXE/TC 标志通知 CPU 填充更多数据接收RX 引脚采样比特 → Rx 移位寄存器 → RX_FIFO → RDR (DATA) → CPU 读取RX 引脚检测起始位下降沿波特率时钟逐位采样电平存入Rx 移位寄存器收满完整 1 字节含校验校验后硬件并行送入RX_FIFO移位寄存器立刻清空可继续收下一帧RX_FIFO 持续缓存多字节当缓存字节达到中断触发阈值如 1/4 满、半满置 RXNE 中断标志CPU 响应中断循环读取RDRDATA 接收寄存器批量取出 FIFO 内所有数据全部读取后 RX_FIFO 空位释放继续缓存后续接收字节.关闭FIFO发送CPU 写 TDR (DATA) → Tx 移位寄存器 → TX 引脚CPU 等待TXE1TDR 为空写入数据到 TDR硬件瞬间将 TDR 字节载入 Tx 移位寄存器TDR 变空TXE 标志置 1移位寄存器逐位串行输出移位寄存器发完前TDR 不能送入下一字节否则阻塞、丢帧接收RX 引脚采样比特 → Rx 移位寄存器 → RDR (DATA) → CPU 读取移位寄存器收满 1 字节立刻并行拷贝至 RDRDATA置RXNE1CPU 必须在下一字节收完前读取 RDR若未及时读取新字节会覆盖 RDR产生数据溢出丢失读取 RDR 硬件自动清零 RXNE 标志移位寄存器继续接收下一帧概要·移位寄存器永远是最底层所有数据最终都要经过它才能进出引脚不受 FIFO 开关影响·DATA 寄存器是 CPU 唯一入口FIFO 只是中间缓冲没有 FIFO 时 DATA 直接对接移位寄存器·无 FIFO 风险每收发 1 字节就要进一次中断若接收方接受慢、发送方发送快外部高速数据流持续从 RX 引脚输入移位寄存器正在组装新的一字节此时 RDRDATA 寄存器里还存放着上一帧未被 CPU 读取的数据新字节组装完成后硬件无处存放新数据直接触发溢出Overrun新字节被丢弃产生丢数即高速串口极易丢数据。开启 FIFO 支持批量收发中断次数大幅减少开启 FIFO 后会提供 8/16/32 字节硬件缓存 就算 CPU 临时处理缓慢新数据可以先存入 FIFO 队列给 CPU 留出批量读取的缓冲时间大幅降低溢出丢包概率。·发送方向TDR 写完先进 FIFO再给移位寄存器接收方向移位寄存器收完先进 FIFOCPU 再从 DATA 读 FIFO 数据·移位寄存器、FIFO 均无寄存器映射地址程序员代码中只能操作 DATA 寄存器。·发送CPU 写 DATA → FIFO 缓存 → 移位逐位发 TX·接收RX 采样进移位 → FIFO 缓存 → CPU 读 DATA 取数据FIFO 是蓄水池DATA 是门窗移位寄存器是搬运比特的底层流水线。.通讯过程UART发送数据时先发低位后发高位。当总线处于空闲状态时线路保持高电平。以发送数据0x96为例发送数据前会先发一个0让总线从高电平变成低电平提醒数据接收方做好准备然后依次从低位到高位发送八位数据。传输完成后会发一个1让总线重新回到高电平。UART数据发送过程中包含8位数据位一位起始位一位停止位。一共10位。如若需要发送新的数据则重新从起始位开始。UART属于异步通讯这意味着没有时钟信号取而代之的是在数据包中添加开始和停止位。这些位定义了数据包的开始和结束因此接收UART知道何时读取这些数据。个人理解单片机设备和PC串口调试通讯时1.单片机发送字符串发送前STAT寄存器发送bit状态为空此时往DATA寄存器上写一个字符即发送了一个字符STAT寄存器发送bit状态变为满此时PC串口调试助手马上就收一个字符STAT寄存器发送bit状态变为空依次2.单片机接受字符接受前STAT寄存器接受bit为满从DATA寄存器读取一个字符后STAT寄存器接受bit变为空。此时PC串口调试助手检测到STAT发送bit状态为空马上又发送一个字符STAT寄存器接受bit变为满依次二、S32K44 UART通讯备注各位读者在以下代码有什么问题比如时钟为什么要这样设置、引脚为什么这样设置、波特率这样计算等都可以留言提出来我会一一解答因为我在自己摸索过程中也踩雷不少希望借该文章对同行尽力所能及的帮助。1.主要寄存器说明BAUD备注UART 是异步串行通信收发双方没有共享时钟线完全依靠约定相同波特率来同步每一位的采样时刻 接收端按固定时间间隔波特率倒数对 RX 引脚电平采样 一旦波特率不同采样点会持续偏移最终解析不出正确字节。配置生成波特率CTRL是能串口功能STAT判断通讯是否可以进行DATA数据收发2.三种通讯方式2.1.使用DATA寄存器未使用FIFO通讯使用中断方式接受数据直接往DATA写数据进行发送。源码如下读者可以直接复制使用clock.c#include S32K144.h void SOSC_init_8MHz(void) { SCG-SOSCDIV0x00000101; /* SOSCDIV1 SOSCDIV2 1: divide by 1 */ SCG-SOSCCFG0x00000024; /* Range2: Medium freq (SOSC betw 1MHz-8MHz)*/ /* HGO0: Config xtal osc for low power */ /* EREFS1: Input is external XTAL */ while(SCG-SOSCCSR SCG_SOSCCSR_LK_MASK); /* Ensure SOSCCSR unlocked */ SCG-SOSCCSR0x00000001; /* LK0: SOSCCSR can be written */ /* SOSCCMRE0: OSC CLK monitor IRQ if enabled */ /* SOSCCM0: OSC CLK monitor disabled */ /* SOSCERCLKEN0: Sys OSC 3V ERCLK output clk disabled */ /* SOSCLPEN0: Sys OSC disabled in VLP modes */ /* SOSCSTEN0: Sys OSC disabled in Stop modes */ /* SOSCEN1: Enable oscillator */ while(!(SCG-SOSCCSR SCG_SOSCCSR_SOSCVLD_MASK)); /* Wait for sys OSC clk valid */ } void SPLL_init_160MHz(void) { while(SCG-SPLLCSR SCG_SPLLCSR_LK_MASK); /* Ensure SPLLCSR unlocked */ SCG-SPLLCSR 0x00000000; /* SPLLEN0: SPLL is disabled (default) */ SCG-SPLLDIV 0x00000302; /* SPLLDIV1 divide by 2; SPLLDIV2 divide by 4 */ SCG-SPLLCFG 0x00180000; /* PREDIV0: Divide SOSC_CLK by 011 */ /* MULT24: Multiply sys pll by 16 2440 */ /* SPLL_CLK 8MHz / 1 * 40 / 2 160 MHz */ while(SCG-SPLLCSR SCG_SPLLCSR_LK_MASK); /* Ensure SPLLCSR unlocked */ SCG-SPLLCSR 0x00000001; /* LK0: SPLLCSR can be written */ /* SPLLCMRE0: SPLL CLK monitor IRQ if enabled */ /* SPLLCM0: SPLL CLK monitor disabled */ /* SPLLSTEN0: SPLL disabled in Stop modes */ /* SPLLEN1: Enable SPLL */ while(!(SCG-SPLLCSR SCG_SPLLCSR_SPLLVLD_MASK)); /* Wait for SPLL valid */ } void NormalRUNmode_80MHz (void) { /* Change to normal RUN mode with 8MHz SOSC, 80 MHz PLL*/ SCG-RCCRSCG_RCCR_SCS(6) /* PLL as clock source*/ |SCG_RCCR_DIVCORE(0b01) /* DIVCORE1, div. by 2: Core clock 160/2 MHz 80 MHz*/ |SCG_RCCR_DIVBUS(0b01) /* DIVBUS1, div. by 2: bus clock 40 MHz*/ |SCG_RCCR_DIVSLOW(0b10); /* DIVSLOW2, div. by 2: SCG slow, flash clock 26 2/3 MHz*/ if ((SCG-CSR SCG_CSR_SCS_MASK SCG_CSR_SCS_SHIFT ) ! 6) {} /* Wait for sys clk src SPLL */ } void init_clks_80MHz(void) { // SMC-PMPROT SMC_PMPROT_AVLP_MASK; //allow VLPS mode // SMC-STOPCTRL SMC_STOPCTRL_STOPO(1); //1:BOTH system and bus clock disable;2:system clock disable, bus clock enabled // SMC-PMCTRL 0x00000002;// SMC_PMCTRL_RUNM_MASK; //select very-low-power stop // while (!(SMC-PMSTAT 1)){ ; } //wait RUN ok. SOSC_init_8MHz(); SPLL_init_160MHz(); NormalRUNmode_80MHz(); }uart.c/* * LPUART.c Copyright NXP 2016 * Description: LPUART functions * 2015 Sept 28 Kushal Shaw - original version AN5213; * 2016 Mar 17 O Romero - ported to S32K144; * 2017 Jul 03 SM: Correced receive spelling for function */ #include S32K144.h /* include peripheral declarations S32K144 */ #include uart.h #include string.h #include stdarg.h #include stdio.h UART_DATA_t uart_data; /* 数据位8bit 优化其他bit数据通讯7、9、10 停止位1bit 优化2bit停止位 校验位disable 优化开启奇偶检验 数据通讯方式UART模块DATA寄存器 优化1.DMA2.FIFO 轮询3.FIFO中断1字节或者N字节中断 实验 1.LPUART_s32K144工程循环收1个字节看是否能接收字符串 2.在lpuart_echo_s32k144工程上改变接收长度1-N看是否能接收字符串 3.在lpuart_echo_s32k144工程上改变数据位、停止位、校验位通讯 4.优化当前代码通过参数输入选择数据位、停止位、校验位、通讯方式进行正常通讯 */ void set_baud(void) { // look for best suitable BAUD U32 osr 4, tempDiff, calculatedBaud, baudDiff; U16 sbr, sbrTemp, i; // First calculate the baud rate using the minimum OSR possible sbr (uint16_t)(8000000 / (115200 * osr)); calculatedBaud (8000000 / (osr * sbr)); if (calculatedBaud 115200) { baudDiff calculatedBaud - 115200; } else { baudDiff 115200 - calculatedBaud; } /* loop to find the best osr value possible, one that generates minimum baudDiff * iterate through the rest of the supported values of osr */ for (i 5U; i 32U; i) { /* calculate the temporary sbr value */ sbrTemp (uint16_t)(8000000 / (115200 * i)); /* calculate the baud rate LPUART1d on the temporary osr and sbr values */ calculatedBaud (8000000 / (i * sbrTemp)); if (calculatedBaud 115200) { tempDiff calculatedBaud - 115200; } else { tempDiff 115200 - calculatedBaud; } if (tempDiff baudDiff) { baudDiff tempDiff; osr i; /* update and store the best osr value calculated */ sbr sbrTemp; /* update store the best sbr value calculated */ } } /* Check if osr is between 4x and 7x oversampling. * If so, then BOTHEDGE sampling must be turned on */ if ((osr 3U) (osr 8U)) { LPUART1-BAUD | (LPUART1-BAUD ~LPUART_BAUD_BOTHEDGE_MASK) | (1 LPUART_BAUD_BOTHEDGE_SHIFT); } /* program the osr value (bit value is one less than actual value) */ // LPUART1-BAUD ~(LPUART_BAUD_OSR_MASK); tempDiff LPUART1-BAUD; tempDiff ~(LPUART_BAUD_OSR_MASK); tempDiff | LPUART_BAUD_OSR(osr - 1); LPUART1-BAUD tempDiff; // LPUART1-BAUD ~(0x1f 24); // LPUART1-BAUD | (osr - 1) 24; /* write the sbr value to the BAUD registers */ LPUART1-BAUD ~(LPUART_BAUD_SBR_MASK); LPUART1-BAUD | sbr 0; } void LPUART1_init(void) /* Init. summary: 9600 baud, 1 stop bit, 8 bit format, no parity */ { PCC-PCCn[PCC_LPUART1_INDEX] ~PCC_PCCn_CGC_MASK; /* Ensure clk disabled for config */ PCC-PCCn[PCC_LPUART1_INDEX] | PCC_PCCn_PCS(0b001) /* Clock Src 1 (SOSCDIV2_CLK) */ | PCC_PCCn_CGC_MASK; /* Enable clock for LPUART1 regs */ set_baud(); //LPUART1-BAUD 0x0F000034; /* Initialize for 9600 baud, 1 stop: */ /* SBR52 (0x34): baud divisor 8M/9600/16 ~52 */ /* OSR15: Over sampling ratio 15116 */ /* SBNS0: One stop bit */ /* BOTHEDGE0: receiver samples only on rising edge */ /* M100: Rx and Tx use 7 to 9 bit data characters */ /* RESYNCDIS0: Resync during recd data word supported */ /* LBKDIE, RXEDGIE0: interrupts disable */ /* TDMAE, RDMAE, TDMAE0: DMA requests disabled */ /* MAEN1, MAEN2, MATCFG0: Match disabled */ LPUART1-CTRL0x000C0000; /* Enable transmitter receiver, no parity, 8 bit char: */ /* RE1: Receiver enabled */ /* TE1: Transmitter enabled */ /* PE,PT0: No hw parity generation or checking */ /* M7,M,R8T9,R9T80: 8-bit data characters*/ /* DOZEEN0: LPUART enabled in Doze mode */ /* ORIE,NEIE,FEIE,PEIE,TIE,TCIE,RIE,ILIE,MA1IE,MA2IE0: no IRQ*/ /* TxDIR0: TxD pin is input if in single-wire mode */ /* TXINV0: TRansmit data not inverted */ /* RWU,WAKE0: normal operation; rcvr not in statndby */ /* IDLCFG0: one idle character */ /* ILT0: Idle char bit count starts after start bit */ /* SBK0: Normal transmitter operation - no break char */ /* LOOPS,RSRC0: no loop back */ // Enable LPUART interrupt. S32_NVIC-ISER[(uint32_t)(LPUART1_RxTx_IRQn) 5U] (uint32_t)(1UL ((uint32_t)(LPUART1_RxTx_IRQn) (uint32_t)0x1FU)); } void LPUART1_transmit_char(char send) { /* Function to Transmit single Char */ while((LPUART1-STAT LPUART_STAT_TDRE_MASK)LPUART_STAT_TDRE_SHIFT0); /* Wait for transmit buffer to be empty */ LPUART1-DATAsend; /* Send data */ } void LPUART1_transmit_string(char data_string[]) { /* Function to Transmit whole string */ uint32_t i0; while(data_string[i] ! \0) { /* Send chars one at a time */ LPUART1_transmit_char(data_string[i]); i; } } char LPUART1_receive_char(void) { /* Function to Receive single Char */ char recieve; while((LPUART1-STAT LPUART_STAT_RDRF_MASK)LPUART_STAT_RDRF_SHIFT0); /* Wait for received buffer to be full */ recieve LPUART1-DATA; /* Read received data*/ return recieve; } void LPUART1_receive_and_echo_char(void) { /* Function to echo received char back */ char send[RECV_LEN 2] {0}; char buf[RECV_LEN 2] {0}; short i 0; if ((LPUART1-STAT LPUART_STAT_RDRF_SHIFT) || (LPUART1-CTRL LPUART_CTRL_RIE_SHIFT)) { // err buf[i] LPUART1-DATA; // 读数据清RDRF兜底 LPUART1_transmit_string(buf); } for (i 0; i RECV_LEN; i) { buf[i] a; } uart_data.rxBuff send; uart_data.rxSize RECV_LEN 2; // 2用于存放\r\n两字符 LOG(start recv! recvlen:%d, out:0x%x, str:%s\n, 1048574, 0x12345678, buf); /* Enable receive data full interrupt */ LPUART1-CTRL | 1 LPUART_CTRL_RIE_SHIFT; while (uart_data.rxSize); if (!strncmp(send, buf, strlen(buf))) { LPUART1_transmit_string(罗紫屹努力考701\r\n); } } void LPUART1_RxTx_IRQHandler(void) { UART_DATA_t *data_type uart_data; /* Handle receive data full interrupt */ if (LPUART1-CTRL LPUART_CTRL_RIE_SHIFT) { if (LPUART1-STAT LPUART_STAT_RDRF_SHIFT) { /* Get data and put in receive buffer */ // 8 bit per char, 9 and 10bit ??? TODO: *data_type-rxBuff (U8)LPUART1-DATA; /* Update the internal state */ data_type-rxBuff; --data_type-rxSize; /* Finish reception if this was the last byte received */ if (data_type-rxSize 0U) { /* Complete transfer, will disable rx interrupt */ LPUART1-CTRL ~(1 LPUART_CTRL_RIE_SHIFT) ; } } } } void DecToChar(U8 *num) { assert(num); U8 HexChar[16] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F }; if (*num 0) { *num HexChar[0]; } else if (*num 1) { *num HexChar[1]; } else if (*num 2) { *num HexChar[2]; } else if (*num 3) { *num HexChar[3]; } else if (*num 4) { *num HexChar[4]; } else if (*num 5) { *num HexChar[5]; } else if (*num 6) { *num HexChar[6]; } else if (*num 7) { *num HexChar[7]; } else if (*num 8) { *num HexChar[8]; } else if (*num 9) { *num HexChar[9]; } else if (*num 10) { *num HexChar[10]; } else if (*num 11) { *num HexChar[11]; } else if (*num 12) { *num HexChar[12]; } else if (*num 13) { *num HexChar[13]; } else if (*num 14) { *num HexChar[14]; } else if (*num 15) { *num HexChar[15]; } } void DecToHexStr(U32 DecNum, U8 *dest, U16 *index) { U32 HexI 1; U8 HexP 0; U8 str[9] {0}; U8 i 0; U8 len; while (HexI 0) { HexI DecNum / 16; HexP DecNum % 16; DecNum HexI; DecToChar(HexP); str[i] HexP; } len strlen(str); for (i 0; str[i] ! 0; i) { *dest str[len - 1 - i]; *index 1; } } void self_printf(const U8* format, ...) { va_list ap; U16 i 0; U8 buf[1024] {0}; va_start(ap, format); while (*format ! 0) { if (*format %) { if (*(format 1) c) { buf[i] va_arg(ap, char); } else if (*(format 1) d) { sprintf(buf[i], %u, va_arg(ap, U32)); i strlen(buf[i]); } else if (*(format 1) x) { // sprintf(buf[i], %x, va_arg(ap, U32)); // i strlen(buf[i]); DecToHexStr(va_arg(ap, int), buf[i], i); } else if (*(format 1) s) { strcpy(buf[i], (char *)va_arg(ap, U32)); i strlen(buf[i]); } else if (*(format 1) p) { } format 2; } else { buf[i] *format; } } buf[i] 0; LPUART1_transmit_string(buf); }uart.h/* * LPUART.h * * Created on: Mar 17, 2016 * Author: B46911 */ #ifndef LPUART_H_ #define LPUART_H_ #include common.h typedef struct uart_data_type { char *rxBuff; U32 rxSize; char *txBuff; U32 txSize; } UART_DATA_t; /* * 1.DMA * 2.非FIFO轮询 * 3.非FIFO中断 * 4.FIFO 轮询 * 5.FIFO中断1字节或者N字节中断 */ enum communicate { E_DMA, E_NO_FIFO_POLL, E_NO_FIFO_IRQ, // 中断接受时应用层不知道接受的数据有多长接受数据长度固定此时每接受一个字节8bit传输会产生一次中断若没有中断认为数据接受完 E_FIFO_POLL, E_FIFO_IRQ }; #define COMMUNICATE_MODE 2 #define RECV_LEN 258 void LPUART1_init(void); void LPUART1_transmit_char(char send); void LPUART1_transmit_string(char data_string[]); char LPUART1_receive_char(void); void LPUART1_receive_and_echo_char(void); #define LOG(format, ...) self_printf(format, ##__VA_ARGS__); #define LOG1(...) self_printf(__VA_ARGS__); #endif /* LPUART_H_ */main.c#include clock.h #include can.h #include io.h #include systick.h #include wdog.h #include timer.h #include common.h #include adc.h #include get_various_clock.h #include uart.h #include rtc.h int main() { // U32 adc_value; // U8 buf[8]; // U8 can_buf[8] { 0 }; // U8 i 0; init_clks_80MHz(); // 研究寄存器 port_init(); // FLEXCAN0_init(); // 研究寄存器 LPUART1_init(); // RTC_Init(); // systick_init(80000000); // TimerInt(); // wdog_init(); // adc_init(); // flash_init(); while (1) { //led_funtion(); // if (0x777 FLEXCAN0_receive_msg(can_buf)) // { // FLEXCAN0_transmit_msg(12345678, 0x123); // } // if (i 8) { // i 0; // } LPUART1_receive_and_echo_char(); // wdg and uart module 相互影响 // //wdtExtReset(); //read_adc_value(adc_value); // datas[0]; // FLASH_DRV_EraseSector(flashSSDConfig, 0x31000, 4096); // FLASH_DRV_Program(flashSSDConfig, 0x31000, 32, datas); //wdog_feed(); } return 0; }io.c/* * io.c * * Created on: 2022年7月15日 * Author: Administrator */ #include io.h #include systick.h #include timer.h #include common.h #include S32K144.h /************************************* * 输入参数NO * 输出参数NO * 函数功能芯片IO口初始化包括按键1中断初始化 * 返回值NO *************************************/ void port_init(void) { unsigned char i; // PTA // enble PTA端口clock PCC-PCCn[PCC_PORTA_INDEX] | PCC_PCCn_CGC_MASK; // Enable clock for PORTA // 配置PORTA之 A0/A1/A2/A3为 GPIO输出分别对应开发板上的4个小灯LED1/LED2/LED3/LED4 // 管脚复用为GPIO for (i 0; i 4; i) { PTA-PDDR | 1 i; // Port An: Data Direction output PORTA-PCR[i] 0x100; // Port A0: MUX ALT1, GPIO } // PTB //PCC-PCCn[PCC_PORTB_INDEX] | PCC_PCCn_CGC_MASK; // Enable clock for PORTB //PTC // PTC10 key1 PCC-PCCn[PCC_PORTC_INDEX] | PCC_PCCn_CGC_MASK; // Enable clock for PORTC PTC-PDDR ~(1 10); // Port An: Data Direction input PORTC-PCR[10] 0xa0100; // Port A0: MUX ALT1, GPIO // interrupt on falling-edge // UART PORTC-PCR[6]|PORT_PCR_MUX(2); /* Port C6: MUX ALT2,UART1 TX */ PORTC-PCR[7]|PORT_PCR_MUX(2); /* Port C7: MUX ALT2,UART1 RX */ // 外部中断配置 S32_NVIC-ICPR[1] 1 (PORTC_IRQn % 32); S32_NVIC-ISER[(uint32_t)(PORTC_IRQn) 5U] (uint32_t)(1UL ((uint32_t)(PORTC_IRQn) (uint32_t)0x1FU)); // PTD PCC-PCCn[PCC_PORTD_INDEX] | PCC_PCCn_CGC_MASK; // Enable clock for PORTD // PTD13, RTC_CLKOUT PORTD-PCR[13] ~PORT_PCR_MUX_MASK; PORTD-PCR[13] | PORT_PCR_MUX(7); //PTE /* CAN RX TX PTE4 PTE5*/ PCC-PCCn[PCC_PORTE_INDEX] | PCC_PCCn_CGC_MASK; /* Enable clock for PORTE */ PORTE-PCR[4] | PORT_PCR_MUX(5); /* Port E4: MUX ALT5, CAN0_RX */ PORTE-PCR[5] | PORT_PCR_MUX(5); /* Port E5: MUX ALT5, CAN0_TX */ } void PORTC_IRQHandler() { U8 i; U8 j 2; PTA-PDOR 15; while (j) { for (i 0; i 4; i) { PTA-PDOR ~(1 i); timer_delay(); // 这里不能使用systick_delay_times做延时系统滴答靠滴答中断计数此时还未退出按键中断 PTA-PDOR | 1 i; timer_delay(); } j--; } PORTC-ISFR | 1 10; //清除中断标志位 } void led_funtion(void) { uint8_t i; PTA-PDOR 15; for (i 0; i 4; i) { PTA-PDOR ~(1 i); systick_delay_times(100); PTA-PDOR | 1 i; systick_delay_times(100); } }2.2.使用DATA寄存器且使用FIFO通讯使用中断带有FIFO的方式收、发数据。源码如下读者可以直接复制使用额外寄存器配置FIFOWATER:代码初始化时配置FIFO和WATER寄存器需要注意在收发使能前设置These register must be written only when CTRL[RE] and CTRL[TE] are cleared。中断产生条件FIFO中接收的字数要大于设置的RXFIFO数才产生中断RXFIFOSIZE为只读复位值为1即FIFO深度芯片固定为4不可设定RXWATER为2bit设置最大设置值为3。当设置为3发送字节小于3时就不会产生中断。When the number of datawords in the receive FIFO/buffer is greater than the value in this register field, an interrupt or a DMA request is generated。LPUART1-CTRL ~((1 18) | (1 19)); LPUART1-FIFO | ((1 7) | (1 3)); LPUART1-WATER | (3 16);2.3.使用FIFO轮询通讯轮询就是周期性去操作DATA寄存器。这里说明一下数据位非8bit通讯方式如9bit10bitCTRL9bit/10bit数据需要2字节前8bit直接操作DATA寄存器剩下的1/2bit有CTRL寄存器操作void LPUART_Putchar10(LPUART_Type * base, uint16_t data) { uint8_t ninthDataBit, tenthDataBit; uint32_t ctrlRegVal; volatile uint8_t * dataRegBytes (volatile uint8_t *)((base-DATA)); ninthDataBit (uint8_t)((data 8U) 0x1U); tenthDataBit (uint8_t)((data 9U) 0x1U); /* write to ninth/tenth data bit (T[0:7]8-bits, T89th bit, T910th bit) */ ctrlRegVal base-CTRL; ctrlRegVal (ctrlRegVal ~LPUART_CTRL_R9T8_MASK) | ((uint32_t)ninthDataBit LPUART_CTRL_R9T8_SHIFT); ctrlRegVal (ctrlRegVal ~LPUART_CTRL_R8T9_MASK) | ((uint32_t)tenthDataBit LPUART_CTRL_R8T9_SHIFT); base-CTRL ctrlRegVal; /* write to 8-bits to the data register */ dataRegBytes[0] (uint8_t)data; }