具起来rs232和485电平的区别硬件外围芯片,波特率(反映传一位的时间),起始位和停止位,数据宽度,校验,硬件流控制,相应连接电脑时的接口怎么样的。配置,使用函数,中断,查询并结合通信协议才算了解了串口使用。
以上是基础,当然stm很多相关复用功能,支持同步单向通信和半双工单线通信,支持局部互联网、智能卡协议和红外数据组织相关规范,以及调制解调器操作,运行多处理器通信。同时可以使用DMA方式进行高速数据通信。注意Print函数时间问题,尝试通过DMA解决。
特点:全双工,异步,分数波特率发生器好处是速度快,位数8或9为,可配置1或2停止位,Lin协议,可提供同步时钟功能。
硬件上
一般2个脚,RX和TX;同步模式需要SCLK时钟脚,红外IRDA需要irDA_RDI脚作为数据输入和irDA_TDO输出。
奇偶校验通过usart_cr1 pce位配置校验(发送生成奇偶位,接受时进行校验)
LIN局域互联网模式:通过设置USART_CR2中LINEN位配置,使用的时候需要外加专门的收发器才可以
同步模式:通过设置USART_CR2中CLKEN位配置
智能卡模式: 通过设置USART_CR3中SCEN位配置
DMA、硬件流控制作专门研究。
中断有哪些事件?
发送数据寄存器空 发送完成 接受数据可读 奇偶校验错数据溢出 CTS标志 空闲标志 断开标志 噪声标志
遗憾是没有留有接受缓冲区,用查询容易数据丢失
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
流程是时钟配置管脚配置(如重映射,管脚模式)-串口配置-中断配置--相应中断--打开串口
上面是一些基础知识点,下面从实际运用来了解串口功能
比较简单些的应用吧:对usart进行初始化的工作
void COM1_Init( void)
{
//首先要初始化结构体:少不了对于的引脚,忘不了usart,更牵挂着中断的配置结构体,定义空间来被涂鸦
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//下面是对GPIO进行涂鸦
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //选择管脚位
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //模式复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //选择管脚位
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //模式为输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure);
//使能串口中断,并设置优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART1_IRQn_Priority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); //将结构体丢到配置函数,即写入到对应寄存器中
//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//所有的工作都做好了,最后别忘了打开串口
USART_Cmd(USART1, ENABLE);
}
//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);下面是中断源
#define USART_IT_PE ((uint16_t)0x0028)
#define USART_IT_TXE ((uint16_t)0x0727)
#define USART_IT_TC ((uint16_t)0x0626)
#define USART_IT_RXNE ((uint16_t)0x0525)
#define USART_IT_IDLE ((uint16_t)0x0424)
#define USART_IT_LBD ((uint16_t)0x0846)
#define USART_IT_CTS ((uint16_t)0x096A)
#define USART_IT_ERR ((uint16_t)0x0060)
#define USART_IT_ORE ((uint16_t)0x0360)
#define USART_IT_NE ((uint16_t)0x0260)
#define USART_IT_FE ((uint16_t)0x0160)
--
以上是初始化配置,下面还要构成最小的运用,就举例输出函数吧
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的理解
stm32 DMA有8通道,07
既然DMA传输的是数据,当然有数据的宽度了,这需要配置。另外还要有地址吧,从哪个地址开始传,还有传到哪个地址,需要配置。还有传输普通的就直接传完就好了,如果要高速不断循环传输,这也可以配置。还有从ROM直接快速的加载到RAM(反过来不可以)也可以的。
之上就是一些基本需要配置的工作
DMA_DeInit(DMA1_Channel4);
上面这句是给DMA配置通道,根据ST提供的资料,STM3210Fx中DMA包含7个通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_TypeDef *)USART1)->DR);
上面是设置外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) USART_DMA_BUF;
上面这句很显然是DMA要连接在Memory中变量的地址,上面设置存储器地址;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
上面的这句是设置DMA的传输方向,就如前面我所说的,从存储器到外设,也可以从外设到存储器,:把DMA_DIR_PeripheralSRC改成DMA_DIR_PeripheralDST即可。
DMA_InitStructure.DMA_BufferSize = 0;
上面的这句是设置DMA在传输时缓冲区的长度,前面有定义过了buffer的起始地址:为了安全性和可靠性,一般需要给buffer定义一个储存片区,这个参数的单位有三种类型:Byte、HalfWord、word,我设置的2个half-word(见下面的设置);32位的MCU中1个half-word占16 bits。
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
上面的这句是设置DMA的外设递增模式,如果DMA选用的通道(CHx)有多个外设连接,需要使用外设递增模式:DMA_PeripheralInc_Enable;我的例子选用DMA_PeripheralInc_Disable
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
上面的这句是设置DMA的内存递增模式,DMA访问多个内存参数时,需要使用DMA_MemoryInc_Enable,当DMA只访问一个内存参数时,可设置成:DMA_MemoryInc_Disable。
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
上面的这句是设置DMA在访问时每次操作的数据长度。有三种数据长度类型,前面已经讲过了,这里不在叙述。
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
与上面雷同。在此不再说明。
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
上面的这句是设置DMA的传输模式:连续不断的循环模式,若只想访问一次后就不要访问了(或按指令操作来反问,也就是想要它访问的时候就访问,不要它访问的时候就停止),可以设置成通用模式:DMA_Mode_Normal
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
上面的这句是设置DMA的优先级别:可以分为4级:VeryHigh,High,Medium,Low.
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
上面的这句是设置DMA的2个memory中的变量互相访问的
DMA_Init(DMA_Channel1,&DMA_InitStructure);
前面那些都是对DMA结构体成员的设置,在次再统一对DMA整个模块做一次初始化,使得DMA各成员与上面的参数一致。
DMA_Cmd(DMA_Channel1,ENABLE);
ok上面的配置工作完成了,相当于设定了一根管道通过DMA把缓冲区中要发送的数据发送到串口中。当然要使得DMA与usart1相连接,在usart1中还要把usart的DMA功能打开: USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);接着在程序中只需要监控,数据发送的状态,并适时的打开或关闭DMA,留着下一次的串口发送用。
函数重载的 printf()函数如下
int fputc(int ch, FILE *f)
{
while(En_Usart_Queue(ch)==-1);
return ch;
}
起始就是往环形缓冲区中添加要串口打印的数据,这个动作是比较快的。因为cpu直接移动数据很快,而通过cpu来操作串口,等待收获反映,有个while(..)是比较慢得,故有几个毫秒的延时。现在好了,cpu ,通过printf只是移动数据到了缓冲区,缓冲区在一定的时候,cpu指挥dma来开始接下来的操作,然后dma操作,cpu接着做其他的事情,仅仅只要在下次空闲的时候来查一下dma有木有传输完成,或者有没有传输错误,并改变环形队列首位的位置,以及更改相应的状态就可以了。这样可以大大的节省很多的时间哦。
环形队列的结构,大家可以看一些算法,不是很难的。
下面是运行过程中,cpu操作查询的函数。
void DMA_USART_Handler(void){
u16 num=0;
s16 read;
if(DMA_GetCurrDataCounter(DMA1_Channel4)==0){ //检查DMA是否完成传输任务
DMA_Cmd(DMA1_Channel4, DISABLE);
while((read=De_Usart_Queue())!=-1){
USART_DMA_BUF[num]=read;
num++;
if(num==USART_DMA_BUF_SIZE)
break;
}
if(num>0){
((DMA_Channel_TypeDef *)DMA1_Channel4)->CNDTR = num;//数量寄存器清零
DMA_Cmd(DMA1_Channel4, ENABLE);
}
}
}
一. DMA原理:
DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量 中断 负载。否则,CPU 需要从 来源 把每一片段的资料到 暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。
DMA 传输将数据从一个地址空间到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。
二.STM32使用DMA
1.DMA的设置:
要配置的有DMA传输通道选择,传输的成员和方向、普通模式还是循环模式等等。
{
DMA_InitTypeDef DMA_InitStructure;
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存-->外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //DMA访问的数据地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输数据大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
vu8 SendBuff[SENDBUFF_SIZE];
SendBuff[i] = i+'0';
}
4、开始DMA传输(使能对应的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);
{
LED_1_REV; //LED改变亮灭
Delay(); //浪费时间
}
#include "stm32f10x_lib.h"
#include "stdio.h"
#define USART1_DR_Base 0x40013804
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
void Delay(void);
int main(void)
{
u16 i;
#ifdef DEBUG
debug();
#endif
recv_ptr = 0;
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
USART1_Configuration();
printf("\r\nSystem Start...\r\n");
printf("Initialling SendBuff... \r\n");
for(i=0;i
SendBuff[i] = i+'0';
}
printf("Initial success!\r\nWaiting for transmission...\r\n");
//发送去数据已经准备好,按下按键即开始传输
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));
printf("Start DMA transmission!\r\n");
//这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//开始一次DMA传输!
DMA_Cmd(DMA1_Channel4, ENABLE);
//等待DMA传输完成,此时我们来做另外一些事,点灯
//实际应用中,传输数据期间,可以执行另外的任务
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
Delay(); //浪费时间
}
//DMA传输结束后,自动关闭了DMA通道,而无需手动关闭
//下面的语句被注释
//DMA_Cmd(DMA1_Channel4, DISABLE);
printf("\r\nDMA transmission successful!\r\n");
while (1)
{
}
}
int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
}
void Delay(void)
{
u32 i;
for(i=0;i<0xF0;i++);
return;
}
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
RCC_HSEConfig(RCC_HSE_ON);
//等待外部晶振稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp();
//如果外部晶振启动成功,则进行下一步操作
if(HSEStartUpStatus==SUCCESS)
{
//设置HCLK(AHB时钟)=SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
//推荐值:SYSCLK = 0~24MHz Latency=0
// SYSCLK = 24~48MHz Latency=1
// SYSCLK = 48~72MHz Latency=2
FLASH_SetLatency(FLASH_Latency_2);
//开启FLASH预取指功能
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//启动PLL
RCC_PLLCmd(ENABLE);
//等待PLL稳定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
//系统时钟SYSCLK来自PLL输出
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//切换时钟后等待系统时钟稳定
while(RCC_GetSYSCLKSource()!=0x08);
}
//启动GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_GPIOB \
RCC_APB2Periph_GPIOC RCC_APB2Periph_GPIOD,\
ENABLE);
//启动AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//启动USART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//启动DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 GPIO_Pin_5 GPIO_Pin_6 GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//位于PD口的3 4 11-15脚,使能设置为输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 GPIO_Pin_4 GPIO_Pin_11 GPIO_Pin_12 \
GPIO_Pin_13 GPIO_Pin_14 GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// Set the Vector Table base location at 0x20
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
// Set the Vector Table base location at 0x08
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//串口接收中断打开
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART1_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
}
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存-->外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular (不停地传送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
上一篇:STM32缺陷之一:串口中断标志位缺陷
下一篇:STM32水温控制系统硬件详解
推荐阅读最新更新时间:2024-03-16 14:57
- 热门资源推荐
- 热门放大器推荐
设计资源 培训 开发板 精华推荐
- Allegro MicroSystems 在 2024 年德国慕尼黑电子展上推出先进的磁性和电感式位置感测解决方案
- 左手车钥匙,右手活体检测雷达,UWB上车势在必行!
- 狂飙十年,国产CIS挤上牌桌
- 神盾短刀电池+雷神EM-i超级电混,吉利新能源甩出了两张“王炸”
- 浅谈功能安全之故障(fault),错误(error),失效(failure)
- 智能汽车2.0周期,这几大核心产业链迎来重大机会!
- 美日研发新型电池,宁德时代面临挑战?中国新能源电池产业如何应对?
- Rambus推出业界首款HBM 4控制器IP:背后有哪些技术细节?
- 村田推出高精度汽车用6轴惯性传感器
- 福特获得预充电报警专利 有助于节约成本和应对紧急情况