打印
[其他ST产品]

STM32F1常用外设介绍

[复制链接]
楼主: 范德萨发额
手机看帖
扫描二维码
随时随地手机跟帖
221
范德萨发额|  楼主 | 2023-2-28 21:01 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
获取中断状态

ITStatus DMA_GetITStatus(uint32_t DMAy_IT);

使用特权

评论回复
222
范德萨发额|  楼主 | 2023-2-28 21:01 | 只看该作者
清除中断挂起位

void DMA_ClearITPendingBit(uint32_t DMAy_IT);

使用特权

评论回复
223
范德萨发额|  楼主 | 2023-2-28 21:01 | 只看该作者
DMA程序示例

uint16_t AD_Value[4];

void AD_Init(void)
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
       
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
       
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
       
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//这只规则组
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
               
        ADC_InitTypeDef ADC_InitStructure;
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描模式
        ADC_InitStructure.ADC_NbrOfChannel = 4;//四个通道
        ADC_Init(ADC1, &ADC_InitStructure);
       
        DMA_InitTypeDef DMA_InitStructure;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//源地址
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//半字长
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//不自增
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;//目标地址
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//半字长
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//地址自增
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设到存储器
        DMA_InitStructure.DMA_BufferSize = 4;//传输计数器为4
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//硬件触发
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
       
        DMA_Cmd(DMA1_Channel1, ENABLE);
        ADC_DMACmd(ADC1, ENABLE);//打通ADC到DMA的通道
        ADC_Cmd(ADC1, ENABLE);
       
        ADC_ResetCalibration(ADC1);
        while (ADC_GetResetCalibrationStatus(ADC1) == SET);
        ADC_StartCalibration(ADC1);
        while (ADC_GetCalibrationStatus(ADC1) == SET);
       
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

使用特权

评论回复
224
范德萨发额|  楼主 | 2023-2-28 21:01 | 只看该作者
USART串口
通信接口

    通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统

    通信协议:指定通信的规则,通信双方按照协议规则进行数据收发

    全双工:通信双方能够同时进行双向通信,全双工,一般有两根通信线

    单工:数据只能从一个设备到另一个设备

    TX和RX是单端信号,它们的高低信号都是相对于GND的,严格上来说GND也算是通信线,串口通信的TX,RX,GND是必须要接的。

    串口通信有两根通信线(发送端TX和接收端RX)

    TX和RX要交叉连接

    当只需单向的数据传输时,可以只接一根通信线

    当电平标准不一致时,需要加电平转换芯片

    复杂一点的串口通信还有时钟引脚、硬件流控制的引脚

使用特权

评论回复
225
范德萨发额|  楼主 | 2023-2-28 21:01 | 只看该作者

使用特权

评论回复
226
范德萨发额|  楼主 | 2023-2-28 21:02 | 只看该作者
串口参数及时序

使用特权

评论回复
227
范德萨发额|  楼主 | 2023-2-28 21:02 | 只看该作者
串口数据帧的整体结构:串口中,每一个字节都装载在一个数据帧里面,每个数据帧都由起始位、数据位和停止位组成,数据位有8个,代表一个字节的8位,还可以在数据位的最后加一个奇偶校验位,这样数据位总共就是9位,其中有效载荷时前8位,代表1个字节,校验位跟在有效载荷后面,占1位

使用特权

评论回复
228
范德萨发额|  楼主 | 2023-2-28 21:02 | 只看该作者
波特率:规定串口通信的速率(串口一般使用异步通信,需要双方约定一个通信速率),例如每隔1s发送一位,接收方也要每隔1s接收一位,接收快了,就会重复接收某些位,如果接收慢了,就会漏掉某些位,发送和接收必须约定好速率,波特率本义是每秒传输码元的个数,单位是码元/s,或者直接叫波特(Baud),比特率是每秒传输的比特数,单位是bit/s,或者叫bps,在二进制调制的情况下,一个码元就是一个bit,此时波特率就等于比特率,单片机的串口通信,基本都是二进制调制,也就是高电平表示1,低电平表示0,一位就是1bit,规定波特率为1000bps,表示1s要发1000位,每一位的时间就是1ms,发送方每隔1ms发送一位,接收方每隔1ms接收一位,

使用特权

评论回复
229
范德萨发额|  楼主 | 2023-2-28 21:02 | 只看该作者
起始位:标志一个数据帧的开始,固定为低电平(串口的空闲状态是高电平,没有数据传输的时候引脚必须置高电平,作为空闲状态)需要传输的时候先发送一个起始位,起始位必须是低电平,来打破空闲状态的高电平,产生一个下降沿(告诉接受设备,这一帧数据要开始了),如果没有起始位,当发送8个1的时候,数据线一直都是高电平,没有任何波动,这样接收方就不知道我是否发送数据,所以必须要有一个固定为低电平的起始位,产生下降沿,来告诉接受设备,为要发送数据了-----起始位固定为0,产生下降沿,表示传输开始

使用特权

评论回复
230
范德萨发额|  楼主 | 2023-2-28 21:02 | 只看该作者
停止位;在一个字节数据发送完成后,必须要有一个停止位,这个停止位的作用是,用于数据帧间隔,固定为高电平,同时这个停止位也是为下一个起始位做准备的,如果没有停止位,那当为数据最后一位是0的时候,下次再发送新的一帧,就没法产生下降沿了-----停止位固定为1,把引脚恢复成高电平,方便下一次的下降沿,如果没有数据了,引脚也为高电平,代表空闲状态

使用特权

评论回复
231
范德萨发额|  楼主 | 2023-2-28 21:02 | 只看该作者
数据位:表示数据帧的有效载荷,1为高电平,0位低电平,低位先行

校验位:用于数据验证,是根据数据位计算得来的,串口使用奇偶校验位方法,奇偶校验可以用来判断数据传输是不是出错了,如果数据出错了可以选择丢弃或者要求重传,校验可以选择三种方式,无校验、奇校验和偶校验,无校验就是不需要校验位,波形就是上图左边的,起始位、数据位,停止位一共3个部分,奇校验和偶校验的波形就是上图右边的,起始位、数据位、校验位、停止位,总共4个部分,如果使用了奇校验,那么包括校验位在内的9位数据会出现奇数个1,如果传输 0000 1111,目前总共4个1,是偶数个,那么校验位就需要再补一个1,连同校验位就是0000 1111 1,总共5个1,保证1的个数为奇数,如果数据是0000 1110,此时3个1,是奇数个,那么校验位就补1个0,连同校验位就是0000 1110 0,总共还是3个1,1的个数为奇数,发送方,在发送数据后,会补一个校验位,保证1的个数为奇数,接收方在接收数据后,会验证数据位和校验位,如果1的个数还是奇数,就认为数据没有出错,如果在传输中,因为干扰,有一位由1变成0,或者由0变成1了,那么整个数据的奇偶特性就会变化,接收方一验证,发现1的个数不是奇数,那就认为传输出错,就可以选择丢弃,或者要求重传,这就是奇校验的差错控制方法。如果选择双方约定偶校验,那就是保证1的个数是偶数,校验方法也是同理,但是奇偶校验的检出率不是很高,例如,如果有两位数据同时出错,就特性不变,那就校验不出来了,就能校验只能保证一定程度上的数据校验,如果想要更高的检出率可以选择CRC校验,STM32内部也有CRC外设。

使用特权

评论回复
232
范德萨发额|  楼主 | 2023-2-28 21:03 | 只看该作者
数据位:有两种表示方法,一种是把校验位作为数据位的一部分,另一种就是把校验位和数据位独立开,数据位就是有效载荷,校验位就是独立的1位,在串口助手里就是选择的把数据位和校验位分开描述的方法,总之无论是合在一起,还是分开描述,描述的都是同一个东西

使用特权

评论回复
233
范德萨发额|  楼主 | 2023-2-28 21:03 | 只看该作者

使用特权

评论回复
234
范德萨发额|  楼主 | 2023-2-28 21:03 | 只看该作者
第一个波形:这个波形是发送一个数据0x55时,在TX引脚输出的波形,波特率是9600,每一位的时间就是1/9600,大概是104us,没发送数据的时候是空闲状态高电平,数据帧开始,先发送起始位,产生下降沿,代表数据帧开始,数据0x55转为2进制,低位先行,就是依次发送1010 1010,然后参数是,1位停止,无校验,所以数据帧之后就是停止位,把引脚置回高电平,在STM32中,这个根据字节数据翻转高低电平,是由USART外设自动完成的,不用我们管,也可以软件模拟产生这样的波形,定时器定一个104us的时间,时间到之后,按照数据帧要求,调用GPIO_WriteBit置高低电平,产生一个一模一样的波形,也可以完成串口通信,在TX引脚发送就是置高低电平,在RX引脚接收就是读取高低电平,这也可以由USART外设完成,如果想软件模拟的话那就是定时调用GPIO_ReadInputDataBit来读取每一位,接收的时候也需要一个外部中断,在起始位的下降沿触发,进入接收状态,并且对其采样时钟,然后依次采样8次,这就是接受的逻辑

使用特权

评论回复
235
范德萨发额|  楼主 | 2023-2-28 21:04 | 只看该作者
USART :同步收发器,UART:异步收发器

同步模式一般是为了兼容别的协议或者特殊用途而设计的,并不兼容两个USART之间进行同步同步通信,串口主要还是异步通信

USART (Universal Synchronous/Asynchronous Receiver/Transmitter)

USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可以自动接收RX引脚的数据帧时序,拼接成一个字节数据,存放在数据寄存器里

自带波特率发生器,最高达4.5Mbits/s,起始就是一个分频器,比如APB2总线给个72MHz的频率然后波特率发生器进行一个分频,得到我们想要的波特率时钟,在这个时钟下,进行收发,就是我们指定的通信波特率,

可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)、

使用特权

评论回复
236
范德萨发额|  楼主 | 2023-2-28 21:04 | 只看该作者
可选校验位(无校验/奇校验/偶校验)

支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN,硬件流控制:A设备有个TX向B设备的RX发送数据,A设备一直在发,发的太快了,B处理不过来,如果没有硬件流控制,那B就只能抛弃新数据或者覆盖原数据了,如果有硬件流控制,在硬件电路上,就会多出一根线,如果B没准备好接受,就置高电平,如果准备好了,就置低电平,A接收到了B反馈的准备信号,就只会在B准备好的时候,才发数据,如果B没准备好,那数据就不会发送出去,硬件流控制可以防止处理慢而导致数据丢失的问题,硬件流控制STM32也是有的,但是一般不用,串口也支持DMA数据转运,如果有大量的数据进行收发,可以使用DMA转运数据,减轻CPU的负担

使用特权

评论回复
237
范德萨发额|  楼主 | 2023-2-28 21:04 | 只看该作者
STM32F103C8T6 USART资源:USART1、USART2、USART3,USART1是APB2总线的设备,USART2,3是APB1总线的设备


SW_RX、IRDA_OUT/IN这些是智能卡和IrDA通信的引脚

使用特权

评论回复
238
范德萨发额|  楼主 | 2023-2-28 21:04 | 只看该作者
发送和接收的字节数据存在串口的数据寄存器,数据寄存器分为发送数据寄存器TDR(Transmit),另一个是接收数据寄存器RDR(Receive DR),两个寄存器占用同一个地址,在程序上只表现为一个寄存器,就是数据寄存器DR(Data Register),但实际硬件中,分成了两个寄存器,一个用于发送的TDR,一个用于接收的RDR,TDR是只写的,RDR是只读的,当进行写操作时,数据就写入到TDR,当进行读操作的时候,数据就是从RDR中读出来的,还有两个移位寄存器,一个用于发送,一个用于接受,发送移位寄存器的作用就是,把一个字节的数据一位一位地移出去,正好对应串口协议的波形数据位,例如为在某时刻给TDR写入了0x55这个数据,在寄存器就是二进制存储,0101 0101,此时硬件检测到我写入数据了,就会检查移位寄存器是否有数据正在移位,如果没有,这个0101 0101就会立刻全部移动到发送移位寄存器,准备发送,当数据从TDR移动到移位寄存器的时候会置一个标志位,叫TXE(TX Empty),发送寄存器空,检查这个标志位,如果置1了,就可以在TDR继续写入下一个数据了,当TXE标志位置1时,数据其实还没有发送出去,只要数据从TDR转移到发送移位寄存器了TXE就会置1,我们就可以写入新的数据了,然后发送移位寄存器就会在发生器控制的驱动下,向右移位,然后一位一位地,把数据输出到TX引脚,向右移位,正好与串口协议规定的低位先行是一致的,当数据移位完成后,新的数据就会在此自动地从TDR转移到发送移位寄存器里来,如果当前移位寄存器的移位还没有完成,TDR的数据进行等待,一但移位完成,就会立刻转移过来,TDR和移位寄存器的双重缓存,可以保证连续发送数据的时候,数据帧之间不会有空闲,提高了工作效率,简单来说就是数据一但从TDR转移到发送移位寄存器了,就立刻把下一个数据放在TDR等着,一但转移完毕,新的数据就会立刻跟上,这样做效率比较高。

使用特权

评论回复
239
范德萨发额|  楼主 | 2023-2-28 21:04 | 只看该作者
接收端也是类似的,数据从RX引脚通向接收移位寄存器,在接收器控制器的驱动下,一位一位的读取RX电平,先放在最高位,然后向右移,移位8次后,就能接收板一个字节了,因为串口协议规定是低位先行,所以接受移位寄存器是从个高位往低位方向移动的,之后,当一个字节移位完成之后,这一个字节的数据就会整体地一下子转移到接收数据寄存器RDR里来,在转移的过程中也会置一个标志位,叫RXNE(RX Not Empty),接收数据寄存器非空,当检测到RXNE置1之后,就可以把数据读走了,同样也是两个寄存器进行缓存,当数据从移位寄存器转移到RDR时,就可以直接接受下一帧数据了,这就是USART外设整个的工作流程。发送需要加上帧头帧尾,接收需要剔除帧头帧尾,这些操作内部电路会自动执行。

使用特权

评论回复
240
范德萨发额|  楼主 | 2023-2-28 21:05 | 只看该作者
发送器控制:用来控制发送移位寄存器的工作的

接收器控制:用来控制接受移位寄存器的工作

硬件数据流控制:有两个引脚,一个是nRTS,一个是nCTS,nRTS(Request To Send)是请求发送,是输出脚,也就是告诉别人,我当前能不能接受,nCTS(Clear To Send)是清除发送,是输入脚也就是接受别人的nRTS的信号的,前面的n是低电平有效,使用步骤:找另一个支持流控的串口它的TX接到我的RX,然后我的RTS输出一个能不能接受的反馈信号,接到对方CTS,当我能接收的是吧,RTS就置低电平,请求对方发送,对方的CTS收到后们就可以一直发,当我处理不过来时,比如接收数据寄存器一直没有读,又有新的数据过来了,代表我没有及时处理,那RTS就置高电平,对方CTS接收到之后,就会暂停发送,直到接受数据寄存器被读走,RTS置低电平,新的数据才会继续发送,反过来,TX给对方发送数据时我的CTS就接到对方的RTS,用于判断对方,能不能接收,TX和CTS是一对的,RX和RTS是一对的,CTS和RTS也要交叉连接,这就是流控的工作模式(一般不使用流控)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则