STM32 串口功能 库函数 详解和DMA 串口高级运用(转载)
--
以上是初始化配置,下面还要构成最小的运用,就举例输出函数吧
void PrintUart1(const u8 *Str)
{
while(*Str)
{
USART_SendData(USART1, (unsigned char)*Str++);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}
发送字符是通过查询字符串的状态来来不断的发送下一个数据。
接受数据是通过中断来实现的,把接受的数据放入缓冲区,来实现。有包含协议以后细讲。
想玩电脑串口传输数据,通过printf()来直接在电脑窗口显示是不是很爽?在usart.c函数中加入
//不使用半主机模式
#if 1 //如果没有这段,则需要在target选项中选择使用USE microLIB
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
_sys_exit(int x)
{
x = x;
}
#endif
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (unsigned char)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}
上面数据来源可以通过串口,通过usb,通过无线等等。。。
printf函数有个缺陷,就是花费的时间太多了(毫秒级),总不至于让CPU等几个毫秒就来显示串口吧,那再好的CPU也就费了,那肿么办?可以用DMA!!直接让其它硬件来传这些粗糙的工作。CPU玩重点的其它的活!
先接着讲好串口接受,再说这个DMA,在固件库里面有个文件是专门用来放中断处理函数的
里面有个函数
void USART1_IRQHandler(void)
{
static u8 UartBuf[UART_BUF_LEN];//串口缓冲
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
temp=USART_ReceiveData(USART1);
..............下面就是一些处理,可以用状态机模式来玩,直到填充好串口缓冲数据,并校验正确,不多说
}
}
上面是典型的中断处理函数,结合状态机功能就强大了。讲到操作系统还要进一步的学会运用。
通过上面的学习相信对基本的串口操作有了比较深入的理解了,前面提到printf太慢,这里需要一些改进。
考虑到真正执行串口输出(用DMA其实在几毫秒后完成)比执行完pruntf(立即完成)这个时间点晚个几毫秒对实际应用来说没有任何影响,因此CPU可以在嘀嗒中断中指挥DMA模块完成串口输出的任务。(其实对系统还是有些影响的宏观讲,串口输出的数据其实很少,在大河中放入一杯水,几乎可以忽略不计的)
再解决怎么分配:
定义两个全局缓存区
其中一个缓存区以循环队列的形式组织,每次执行fputc时向其队尾加入一个元素。
另一个缓存区直接以数组的形式组织,作为DMA的源地址。
在嘀嗒中断中按下列顺序完成对DMA的操作
(1)判断循环队列是否为空,如果为空说明当前没有字符串需要通过串口输出直接跳至(6)
(2)判断DMA是否正在工作,如果DMA正在工作说明上次分配的任何没干完直接跳至(6)
(3)从循环队列出队N个字符到数组缓存
(4)告诉DMA本次需传输的字节数N
(5)命令DMA开始传输
(6)结束操作
补充:
1.N的确定方法:若循环队列中元素的个数大于或等于数组缓存区的长度(固定值),则将数组缓存区的
长度赋给N,若循环队列中元素的个数小于数组缓存区的长度则将循环队列元素的个数赋给N
2.循环队列开辟得越大,能缓存的字符串就越多,因此是越大越好.
3.数组缓存区并不是开辟的越大越好,这个值可以做如下的计算得出,假设波特率为115200嘀嗒中断
的周期为2毫秒则在这2毫秒时间内理论上最多可传115200*0.002/10=23个字节。因此把数组缓存区
的大小定到比23稍小一点即可,比如定为20.
代码可正常运行。经测试使用新方案printf一个包含了二十个字符的字符串只需要25微秒的CPU耗时,
而老方案则需要1.76毫秒的CPU耗时。从而可以放心的使用printf调试一些时序要求较高的函数了,
另外因为执行时间段从而printf被重入的概率大大减小。如果需要彻底防止printf被重入的话,可在调用printf之前关中断,在printf执行完之后开中断,代价也仅是可能发生的几十微秒的中断延时而已。
.........................................................................................
下面讲一讲我对DMA的理解
stm32DMA有8通道,07
既然DMA传输的是数据,当然有数据的宽度了,这需要配置。另外还要有地址吧,从哪个地址开始传,还有传到哪个地址,需要配置。还有传输普通的就直接传完就好了,如果要高速不断循环传输,这也可以配置。还有从ROM直接快速的加载到RAM(反过来不可以)也可以的。
之上就是一些基本需要配置的工作
DMA_DeInit(DMA1_Channel4);
上面这句是给DMA配置通道,根据ST提供的资料,STM3210Fx中DMA包含7个通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_TypeDef *)USART1)->DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_Typ
STM32串口功能库函数DM 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)