以下是我学习基于uVision中的STM32F103C8编程的一点感悟和指导,分享出来,希望对大家有所帮助。如果有错误的地方可以留言指出来,我一定耐心听取。相信大家只要付出努力,就一定学有所成!
目录
1.设计思路
2.模块讲解
整理了几天,接下来我来讲解一下如何利用STM32F103C8、蓝牙模块、C语言代码结合进行心率的测量、
数据传输、数据显示。
1.设计思路
本次实践结果一共涉及了LED驱动、按键驱动(KEY)、通用输入和输出(GPIO)、系统通用定时器(TIM)、time中断、嵌套向量寄存器(NVIC),通用同步异步收发器(USART)、模拟\数字转换器(ADC)等内容,并将这些内容有机结合。本次实践结果的主要设计思路:总结所学的知识并进行系统设计–>初始化RCC复位时钟–>初始化GPIO–>初始化NVIC–>初始化系统通用时钟并书写time中断服务函数–>初始化USART并书写USART1_SData()发送数据函数和USART1_IRQHandler()中断服务函数–>初始化模拟/数字转换器(ADC)–>main函数中书写相应逻辑–>点击安装手机蓝牙助手,至此我们的项目就已经可以通过外在传感器来进行心跳监控并可以将数据以八进制形式传输到手机端。再结合led驱动和按键驱动,就可以实现led灯亮暗来反映心跳,利用按键来控制程序的开始、暂停。
2 模块讲解
对于LED驱动、按键驱动、定时器、中断控制器、我就不多详述了。至于DMA模块,可以不用使用,是自己学习的时候学这写的。我主要讲解一下USRT和ADC模数转换器,我来讲解下具体的使用和注意的地方。
2.1 USART模块
模块的功能在用上面的介绍表格中和户手册中有,我主要讲下大家比较在意的使用部分。
void usart_configer()
//声明变量
USART_InitTypeDef USART_INIT;
NVIC_InitTypeDef NVIC_USART_INIT;
GPIO_InitTypeDef GPIO_USART_INIT;
//初始化时钟,要用到两个
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //
//初始化GPIO
GPIO_USART_INIT.GPIO_Pin = GPIO_Pin_9;
GPIO_USART_INIT.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_USART_INIT.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_USART_INIT);
//
GPIO_USART_INIT.GPIO_Pin = GPIO_Pin_10;
GPIO_USART_INIT.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_USART_INIT.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_USART_INIT);
//初始化USART
USART_INIT.USART_BaudRate = 9600;
USART_INIT.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_INIT.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_INIT.USART_Parity = USART_Parity_No;
USART_INIT.USART_StopBits = USART_StopBits_1;
USART_INIT.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USART_INIT);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//初始化NVIC
NVIC_USART_INIT.NVIC_IRQChannel = USART1_IRQn;
NVIC_USART_INIT.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_USART_INIT.NVIC_IRQChannelSubPriority = 1;
NVIC_USART_INIT.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_USART_INIT);
USART_Cmd(USART1,ENABLE);
}
//数据发送函数
void USART1_SData(u8 Data){
USART_SendData(USART1,Data);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET){
;//检测发送完成
}
USART_ClearITPendingBit(USART1,USART_FLAG_TC);
}
u16 Recvdata;//定义16位数据,用来接受测试到的数据
void USART1_IRQHandler(){
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET){
Recvdata = USART_ReceiveData(USART1);
ART_ClearITPendingBit(USART1,USART_IT_RXNE | USART_IT_TXE);
return;
}
2.2ADC模数转换模块
void AD_init(){
ADC_InitTypeDef ADC_1;
GPIO_InitTypeDef GPIO_ADC_INIT;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_ADC_INIT.GPIO_Pin = GPIO_Pin_5;//选用通道PA5传输数据
GPIO_ADC_INIT.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_ADC_INIT.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA,&GPIO_ADC_INIT);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//六分频
//初始化内容根据自己要求定
ADC_1.ADC_Mode = ADC_Mode_Independent;
ADC_1.ADC_ScanConvMode = DISABLE;
ADC_1.ADC_ContinuousConvMode = DISABLE;
ADC_1.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_1.ADC_DataAlign = ADC_DataAlign_Right;
ADC_1.ADC_NbrOfChannel = 1;
ADC_Init(ADC1,&ADC_1);
ADC_Cmd(ADC1,ENABLE);
//校检
ADC_ResetCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)){
;
}
ADC_StartCalibration(ADC1);//
while(ADC_GetCalibrationStatus(ADC1)){//
;
}
return;
}
//获取传感器测试结果,16位
u16 AD_Get_Value(){
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_239Cycles5 );
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软启动
while(! ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)){
;
}
ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//清除标志位
return ADC_GetConversionValue(ADC1);//琥获取数据
}
2.3main模块
主要算法思路:计算100-200个点的平均值,作为中轴线的估计值,然后每次获取的数据的值远大于或者远小于中轴线就算做一次,然后算五秒内多少次,结果在乘12即可。或者算3s的结果乘20,。但是中轴线的值也是可以变化的,浮动变化,每次都考虑新加进来的值
while(1){
if(key_scan() == 0){
if(begin == 0){
allon();
begin = 1;//开始和结束的标志
i = 1;
value = 0.0;
ans = 0;//多少个波形
num = 0;多少个20ms
trend = 0;
t = 0;//用来表示num+100
}
}
if(begin == 1){
while(i < test){
re=AD_Get_Value();
data=(float)re*(3.3/4096);//数据转换成电压
value+=data;
i++;
delay_ms(20);
}
if(i == test){
value = value/100.0;
i++;
}
while(1 && (key_scan() != 0)){
re=AD_Get_Value();
data=(float)re*(3.3/4096);
//计算波峰,消除噪音干扰的波峰
if(data > value){
if((data - value)/value >= 0.0745){
if(trend == 1){
trend = 0;
allon();
}
t--;
}
else{
value += (data - value)/(t + 100 +1);
}
}
else if(data < value){
if((value - data)/value >= 0.0745){
if(trend == 0){
ans++;
trend = 1;
alloff();
}
t--;
}
else{
value -= (value - data)/(t + 100 +1);
}
}
if(num%100==0){
data1 = (int)((float)ans * 3000.0 / ((float)num));
data1+=num%10;
USART1_SData((u8)((data1%100/10)+'0'));
USART1_SData((u8)((data1%10)+'0'));
}
delay_ms(20);
num++;
t++;
}
begin = 0;
alloff();
}
}