本帖最后由 dong_abc 于 2013-12-23 04:35 编辑
很早的时候在keil网站下载了个串口通信的demo程序,写得还不错。工作几年了,看过不少人的串口程序,很少有比这个写的好的(也可能是我见识少吧)虽然只是个小小的串口通信。
一、关键字:软缓冲(前几年的单片机一般都没有串口fifo)、中断接收、中断发送、手动触发、全双工。
- /*----------------------------------------------------------------------------
- * Name: Usart.c
- * Purpose: USART usage for STM32
- * Version: V1.00
- *----------------------------------------------------------------------------
- * This file is part of the uVision/ARM development tools.
- * This software may only be used under the terms of a valid, current,
- * end user licence from KEIL for a compatible version of KEIL software
- * development tools. Nothing else gives you the right to use this software.
- *
- * Copyright (c) 2005-2007 Keil Software. All rights reserved.
- *----------------------------------------------------------------------------*/
- #include <stm32f10x_lib.h> // STM32F10x Library Definitions
- #include <stdio.h>
- #include "STM32_Init.h" // STM32 Initialization
- /*----------------------------------------------------------------------------
- Notes:
- The length of the receive and transmit buffers must be a power of 2.
- Each buffer has a next_in and a next_out index.
- If next_in = next_out, the buffer is empty.
- (next_in - next_out) % buffer_size = the number of characters in the buffer.
- *----------------------------------------------------------------------------*/
- #define TBUF_SIZE 256 /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
- #define RBUF_SIZE 256 /*** Must be a power of 2 (2,4,8,16,32,64,128,256,512,...) ***/
- /*----------------------------------------------------------------------------
- *----------------------------------------------------------------------------*/
- #if TBUF_SIZE < 2
- #error TBUF_SIZE is too small. It must be larger than 1.
- #elif ((TBUF_SIZE & (TBUF_SIZE-1)) != 0)
- #error TBUF_SIZE must be a power of 2.
- #endif
- #if RBUF_SIZE < 2
- #error RBUF_SIZE is too small. It must be larger than 1.
- #elif ((RBUF_SIZE & (RBUF_SIZE-1)) != 0)
- #error RBUF_SIZE must be a power of 2.
- #endif
- /*----------------------------------------------------------------------------
- *----------------------------------------------------------------------------*/
- struct buf_st {
- unsigned int in; // Next In Index
- unsigned int out; // Next Out Index
- char buf [RBUF_SIZE]; // Buffer
- };
- static struct buf_st rbuf = { 0, 0, };
- #define SIO_RBUFLEN ((unsigned short)(rbuf.in - rbuf.out))
- static struct buf_st tbuf = { 0, 0, };
- #define SIO_TBUFLEN ((unsigned short)(tbuf.in - tbuf.out))
- static unsigned int tx_restart = 1; // NZ if TX restart is required
- /*----------------------------------------------------------------------------
- USART1_IRQHandler
- Handles USART1 global interrupt request.
- *----------------------------------------------------------------------------*/
- void USART1_IRQHandler (void) {
- volatile unsigned int IIR;
- struct buf_st *p;
- IIR = USART1->SR;
- if (IIR & USART_FLAG_RXNE) { // read interrupt
- USART1->SR &= ~USART_FLAG_RXNE; // clear interrupt
- p = &rbuf;
- if (((p->in - p->out) & ~(RBUF_SIZE-1)) == 0) {
- p->buf [p->in & (RBUF_SIZE-1)] = (USART1->DR & 0x1FF);
- p->in++;
- }
- }
- if (IIR & USART_FLAG_TXE) {
- USART1->SR &= ~USART_FLAG_TXE; // clear interrupt
- p = &tbuf;
- if (p->in != p->out) {
- USART1->DR = (p->buf [p->out & (TBUF_SIZE-1)] & 0x1FF);
- p->out++;
- tx_restart = 0;
- }
- else {
- tx_restart = 1;
- USART1->CR1 &= ~USART_FLAG_TXE; // disable TX interrupt if nothing to send
- }
- }
- }
- /*------------------------------------------------------------------------------
- buffer_Init
- initialize the buffers
- *------------------------------------------------------------------------------*/
- void buffer_Init (void) {
- tbuf.in = 0; // Clear com buffer indexes
- tbuf.out = 0;
- tx_restart = 1;
- rbuf.in = 0;
- rbuf.out = 0;
- }
- /*------------------------------------------------------------------------------
- SenChar
- transmit a character
- *------------------------------------------------------------------------------*/
- int SendChar (int c) {
- struct buf_st *p = &tbuf;
- // If the buffer is full, return an error value
- if (SIO_TBUFLEN >= TBUF_SIZE)
- return (-1);
-
- p->buf [p->in & (TBUF_SIZE - 1)] = c; // Add data to the transmit buffer.
- p->in++;
- if (tx_restart) { // If transmit interrupt is disabled, enable it
- tx_restart = 0;
- USART1->CR1 |= USART_FLAG_TXE; // enable TX interrupt
- }
- return (0);
- }
- /*------------------------------------------------------------------------------
- GetKey
- receive a character
- *------------------------------------------------------------------------------*/
- int GetKey (void) {
- struct buf_st *p = &rbuf;
- if (SIO_RBUFLEN == 0)
- return (-1);
- return (p->buf [(p->out++) & (RBUF_SIZE - 1)]);
- }
- /*----------------------------------------------------------------------------
- MAIN function
- *----------------------------------------------------------------------------*/
- int main (void) {
- buffer_Init(); // init RX / TX buffers
- stm32_Init (); // STM32 setup
- printf ("Interrupt driven Serial I/O Example\r\n\r\n");
- while (1) { // Loop forever
- unsigned char c;
- printf ("Press a key. ");
- c = getchar ();
- printf ("\r\n");
- printf ("You pressed '%c'.\r\n\r\n", c);
- } // end while
- } // end main
工程文件,初始化有点乱,不过这个是脚本配置的,不需要我们手动配置寄存器。
二、关键字:硬缓冲(带串口fifo)、中断接收、中断发送、手动触发、全双工。
这个程序时新塘mini51的demo,网上也有固件包可以下载。跟上面的程序基本雷同。
- /*---------------------------------------------------------------------------------------------------------*/
- /* Copyright(c) 2011 Nuvoton Technology Corp. All rights reserved. */
- /*---------------------------------------------------------------------------------------------------------*/
- /*-----------------------------------------------------------------------------
- Nuvoton Technoledge Corp creadted by CA11
- XTAL = 12MHz, BPS = 115200
- *-----------------------------------------------------------------------------*/
- #include "Common.h"
- #define RXBUFSIZE 64
- //全局变量
- volatile uint8_t comRbuf[RXBUFSIZE];
- volatile uint16_t comRbytes = 0;
- volatile uint16_t comRhead = 0;
- volatile uint16_t comRtail = 0;
- volatile int32_t g_bWait = 1;
- /****************************************************************************************
- 描述 : UART0中断代码
- ****************************************************************************************/
- void UART0_IRQHandler(void)
- {
- uint8_t bInChar[1]={0xFF};
- if(UA_ISR & RDA_INT) //检查是否接收中断
- {
- printf("\nInput:");
-
- while(UA_ISR & RDA_IF) //检查接收到底数据是否有效
- {
- while (UA_FSR & RX_EMPTY); //等字符
- bInChar[0] = UA_RBR; //读取字符
- printf("%c ", bInChar[0]);
-
- if(bInChar[0] == '0')
- {
- g_bWait = 0;
- }
-
- if(comRbytes < RXBUFSIZE) //测缓冲区满否?
- {
- comRbuf[comRtail] = bInChar[0]; //字符队列
- comRtail = (comRtail == (RXBUFSIZE-1)) ? 0 : (comRtail+1);
- comRbytes++;
- }
- }
- printf("\nTransmission Test:");
- }
- else if(UA_ISR & THRE_INT) //检查是否发送中断
- {
- uint16_t tmp;
- tmp = comRtail;
- if(comRhead != tmp)
- {
- bInChar[0] = comRbuf[comRhead];
-
- while((UA_FSR&TX_FULL) != 0); //发送FIFO满时等待
- UA_THR = bInChar[0]; //发送一个字符
- comRhead = (comRhead == (RXBUFSIZE-1)) ? 0 : (comRhead+1);
- comRbytes--;
- }
- }
- }
- int32_t main()
- {
- Un_Lock_Reg(); //解锁被保护的寄存器位,以便用户访问
- PWRCON = PWRCON & (~XTLCLK_EN) | XTAL12M_EN; //使能外晶振
- while((CLKSTATUS & XTL_STB) == 0); //等12M时钟稳定
- CLKSEL0 = (CLKSEL0 & (~HCLK)) | HCLK_12M_32K; //选12M为系统时钟
- Lock_Reg(); //重新锁被保护的寄存器位
- UART_Init();
- printf("\nUART Sample Demo. (Press '0' to exit)\n");
- UA_IER |= (RDA_IEN | THRE_IEN | RLS_IEN); //使能中断
- NVIC_ISER = UART_INT; //使能NVIC UART中断
- while(g_bWait);
- UA_IER &= ~(RDA_IEN | THRE_IEN | RLS_IEN); //禁中断
- NVIC_ICER = UART_INT; //禁止NVIC UART中断
- printf("\nUART Sample Demo End.\n");
- return 0;
- }
这个工程文件就不上传了,要有固件库才能运行。mini51固件库新塘网站有下载。
以上程序是keil公司和新塘公司的demo,所以粗糙了点,将就着看吧。
如果你有更好的,可以贴上来晒晒。毕竟一个模块写过一次之后就尽量不再做重复劳动了。
|