1.串口
串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段, 其重要性不言而喻。
现在基本上所有的 MCU 都会带有串口, STM32 自然也不例外。
而本次实验主要用到串口,rbt6有3个串口,这里我们用串口2;
①、添加库文件
②、 这里我们主要实现的功能是利用串口发送和接受消息;
变量的定义:
u32 TimeDelay=0;
uint8_t RxBuffer[20]; //接收字符存放数组
uint8_t RxCounter=0 ; //接收到的字符的个数
u8 RXOVER=0; //接收是否完成标志位
usart配置要用到引脚PA2和PA3
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
NVIC_Configuration();
//TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure);
//RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 19200;
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_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
USART_Cmd(USART2, ENABLE);
}
中断配置
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
发送字符:因为usart是按字符发送的,而一般我们的消息是字符串,所以需要自定义一个发送函数;
void USART_SendString(u8 *str)
{
u8 index=0;
do
{
USART_SendData(USART2, str[index]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE)==RESET);
index++;
} while(str[index]!=0);
}
中断服务函数:可在主函数也可在stm32f10x_it.c编写
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == 'x'||RxCounter==20)
{
RxCounter=0;
RXOVER=1;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}
else{
RxBuffer[RxCounter]=temp;
++RxCounter;
}
}
}
这里解释一下
USART中的USART_IT_RXNE,USART_IT_TC,USART_IT_TXE
TXE--写寄存器DR清零
RXNE--读寄存器DR清零,也可软件手动清零
TC-- 读/写寄存器DR清零,也可软件手动清零
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器,另一个是程序看不到的移位寄存器,对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束。
当USART_DR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。
你读串口数据时,是装入弹仓,硬件会将数据移到枪膛,这时,RXNE为1,TC为0,STM32硬件的RX脚正在接收数据,但你还可以装入数据到弹仓,装入后,RXNE为0,TC为0.
TX发送完一个数据后,立即将数据从弹仓移入枪膛,这时,RXNE为1,TC为0.
最后TX发送完数据,你又没有装入新数据,这时。RXNE为1,TC为1.
主程序
int main(void)
{
u8 i;
USART_Config();
STM3210B_LCD_Init();
SysTick_Config(SystemCoreClock/1000);
Delay_Ms(200);
USART_SendString("usart send test\r\n");
USART_SendString("base on ct117e\r\n");
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line1," usart receive test ");
LCD_DisplayStringLine(Line3," Receive: ");
LCD_SetTextColor(White);
LCD_SetBackColor(Blue);
while(1){
if(RXOVER==1)
{
LCD_ClearLine(Line4);
LCD_DisplayStringLine(Line4,RxBuffer);
for(i=0;i<20;i++)
{
RxBuffer[i]=0;
}
RXOVER=0;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
}
}
③、ADC
STM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用,
也可以使用双重模式(提高采样率)。 STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。
它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫
描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正
常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你
的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之
后,规则通道才得以继续转换。
而比赛用的板子有2个adc,其中adc1有18个通道,adc2有16个通道;本次实验主要是为了调节电位器R37输出电压,观察LCD上显示的数值
* ADC工作模式配置:
* ADC1 独立模式,单次转换
用到adc1的 通道8(PB0)
首先是adc库文件
adc的配置:
void ADC_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//PB0-ADC channel 8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
// ADC1 工作模式配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //ad单通道
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件启动而非外部
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; ///顺序进行规则转换的初始化外设
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5); // 规则序列的第一个转换
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);//执行复位校准
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);//执行adc校准
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
/*前面讲解过, ADC 的模式非常多, 包括独
立模式,注入同步模式等等,这里我们选择独立模式,所以参数为 ADC_Mode_Independent。
参数 ADC_ScanConvMode 用来设置是否开启扫描模式, 因为是单次转换,这里我们选择不开
启值 DISABLE 即可。
参数 ADC_ContinuousConvMode 用来设置是否开启连续转换模式,因为是单次转换模式,所以
我们选择不开启连续转换模式, DISABLE 即可。
参数 ADC_ExternalTrigConv 是用来设置启动规则转换组转换的外部事件,这里我们选择软件触
发,选择值为 ADC_ExternalTrigConv_None 即可。
参数 DataAlign 用来设置 ADC 数据对齐方式是左对齐还是右对齐,这里我们选择右对齐方式
ADC_DataAlign_Right。
参数 ADC_NbrOfChannel 用来设置规则序列的长度,这里我们是单次转换,所以值为 1 即可。
在上面的校准完成之后, ADC 就算准备好了。接下来我们要做的就是设置规则序列 1 里面
的通道,采样顺序, 以及通道的采样周期, 然后启动 ADC 转换。在转换结束后,读取 ADC 转
换结果值就是了。 这里设置规则序列通道以及采样周期的函数是:
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,
uint8_t Rank, uint8_t ADC_SampleTime);
我们这里是规则序列中的第 1 个转换,同时采样周期为 13.5,所以设置为:
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5); // 规则序列的第一个转换
*/
数据读取函数
float Read_ADC(void)
{
float ADC_VALUE;
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
Delay_Ms(5);
ADC_VALUE=(ADC_GetConversionValue(ADC1)*3.3)/0XFFF;
return ADC_VALUE;
}
软件开启 ADC 转换的方法是:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的 ADC1 的软件转换启动功能
开启转换之后,就可以获取转换 ADC 转换结果数据, 方法是:
ADC_GetConversionValue(ADC1);
主函数:
int main(void)
{
float adc_temp,tem_temp;
u8 string[20];
u8 string1[20];
SysTick_Config(SystemCoreClock/1000);
ADC_Config();
STM3210B_LCD_Init();
LCD_Clear(White);
LCD_SetTextColor(White);
LCD_SetBackColor(Blue);
LCD_ClearLine(Line0);
LCD_ClearLine(Line1);
LCD_ClearLine(Line2);
LCD_ClearLine(Line3);
LCD_ClearLine(Line4);
LCD_DisplayStringLine(Line1," ADC TEST ");
LCD_DisplayStringLine(Line3," PB0-ADC channel 8 ");
LCD_SetTextColor(Blue);
LCD_SetBackColor(White);
while (1)
{
Delay_Ms(200);
adc_temp=Read_ADC();
tem_temp=(1430-adc_temp*1000)/4.3+25;
sprintf(string,"%s%.3f","ADC Value ",adc_temp);
sprintf(string1,"%s%.3f","Tem Value:",tem_temp);
LCD_DisplayStringLine(Line7,string);
LCD_DisplayStringLine(Line9,string1);
}
}
④、内部温度传感器
与上述配置大同小异,由引脚图,需该改通道为16同时还有计算方法
void ADC_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
// RCC_ADCCLKConfig(RCC_PCLK2_Div4);
// ADC1 工作模式配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5);
ADC_TempSensorVrefintCmd(ENABLE); //使能温度传感器
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
主函数:
int main(void)
{
float adc_temp,tem_temp;
u8 string[20];
SysTick_Config(SystemCoreClock/1000);
ADC_Config();
STM3210B_LCD_Init();
LCD_Clear(White);
LCD_SetTextColor(White);
LCD_SetBackColor(Blue);
LCD_ClearLine(Line0);
LCD_ClearLine(Line1);
LCD_ClearLine(Line2);
LCD_ClearLine(Line3);
LCD_ClearLine(Line4);
LCD_DisplayStringLine(Line1," Tem TEST ");
LCD_DisplayStringLine(Line3," channel 16");
LCD_SetTextColor(Blue);
LCD_SetBackColor(White);
while (1)
{
Delay_Ms(200);
adc_temp=Read_ADC();
tem_temp=(1430-adc_temp*1000)/4.3+25;
sprintf(string,"%s%.3f","Tem Value:",tem_temp);
LCD_DisplayStringLine(Line7,string);
}
}