我是靠谱客的博主 善良百合,这篇文章主要介绍nbiot+stm32的驱动,使用串口2,现在分享给大家,希望可以做个参考。

最近在学NBIOT,做个笔记,stm32f103c8t6+nbiota的串口2驱动函数,串口1输出日志,串口2链接模块

stm32使用不是那么熟悉,刚开始使用原子的串口实验的历程来做,结果就是用电脑模拟可以相互发送数据,发送的AT指令模块也可以接收到并且有应答,就是不知道如何来判断应答的内容,参考了原子的历程后调试成功,在此表示感谢

1、串口2的配置,使用DMA方式,(参考正点原子的历程,在此表示感谢)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART2_RX_BUF[USART2_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. //串口发送缓存区 __align(8) u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节 u16 USART2_RX_STA=0; //接收状态标记 void uart2_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能USART2,GPIOA时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //USART2_TX GPIOA.2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2 //USART2_RX GPIOA.3初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3 //Usart2 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //USART 初始化设置 USART_InitStructure.USART_BaudRate = bound;//串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 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); //初始化串口2 USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); USART_Cmd(USART2, ENABLE); //使能串口2 USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE); //使能串口2的DMA发送 UART_DMA_Config(DMA1_Channel7,(u32)&USART2->DR,(u32)USART2_TX_BUF);//DMA1通道7,外设为串口2,存储器为USART2_TX_BUF USART_Cmd(USART2, ENABLE); //使能串口 TIM4_Init(99,7199); //10ms中断 USART2_RX_STA=0; //清零 TIM4_Set(0); //关闭定时器4 } /串口2,printf 函数 //确保一次发送数据不超过USART2_MAX_SEND_LEN字节 void u2_printf(char* fmt,...) { va_list ap; va_start(ap,fmt); vsprintf((char*)USART2_TX_BUF,fmt,ap); va_end(ap); while(DMA1_Channel7->CNDTR!=0); //等待通道7传输完成 UART_DMA_Enable(DMA1_Channel7,strlen((const char*)USART2_TX_BUF)); //通过dma发送出去 } void USART2_IRQHandler(void) { u8 res,i; if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据 { res =USART_ReceiveData(USART2); if(USART2_RX_STA<USART2_MAX_RECV_LEN) //还可以接收数据 { TIM_SetCounter(TIM4,0); //计数器清空 if(USART2_RX_STA==0)TIM4_Set(1); //使能定时器4的中断 USART2_RX_BUF[USART2_RX_STA++]=res; //记录接收到的值 i++; }else { USART2_RX_STA|=1<<15; //强制标记接收完成 } } if(i%5==0) { if(strstr((const char*)USART2_RX_BUF,"+NNMI")) { u2_printf("AT+NMGR"); printf("ATSEND--> AT+NMGRrn"); } // NBIOT_LED_CONTROL(); } } /***************** 发送字符串 **********************/ void Usart_SendString( USART_TypeDef * pUSARTx, char *str) { USART_SendData(pUSARTx,*str); USART_ClearFlag(pUSARTx,USART_FLAG_TC); while (0!=*str)//等待发送完成 { USART_SendData(pUSARTx,*str); while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);//等待发送完成 str++; } //换行 USART_SendData(pUSARTx,0x0a); USART_SendData(pUSARTx,0x0d); /* 等待发送完成 */ while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET); } //将串口2接收到的数据从串口1打印出来 void USART2_to_USART1(char*date) { // if(USART_GetFlagStatus(USART2,USART_FLAG_IDLE)!=Bit_RESET) // { //if(*date!=0x0a&&*date!=0x0d) Usart_SendString(USART1,date); // Usart_SendString(USART1,"rn"); // len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 // printf("rn您发送的消息为:rn"); // for(t=0;t<len;t++) // { // USART2->DR=*CMD_AT_CFUN; // USART_SendData(USART2,"nihao"); // // while((USART2->SR&0X40)==0);//等待发送结束 // } // printf("rnrn");//插入换行 USART2_RX_STA=0; // } } //设置TIM4的开关 //sta:0,关闭;1,开启; void TIM4_Set(u8 sta) { if(sta) { TIM_SetCounter(TIM4,0); //计数器清空 TIM_Cmd(TIM4, ENABLE); //使能TIMx }else TIM_Cmd(TIM4, DISABLE);//关闭定时器4 } //配置TIM4预装载周期值 void TIM4_SetARR(u16 period) { TIM_SetCounter(TIM4,0); //计数器清空 TIM4->ARR&=0x00; //先清预装载周期值为0 TIM4->ARR|= period; //更新预装载周期值 } //通用定时器中断初始化 //这里始终选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 void TIM4_Init(u16 arr,u16 psc) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能//TIM4时钟使能 //定时器TIM3初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 } //定时器4中断服务程序 void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)//是更新中断 { TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx更新中断标志 // if(Scan_Wtime!=0)//蓝牙扫描模式 // { // i++; // if(i==Scan_Wtime) // { // i=0; // Scan_Wtime = 0; // USART2_RX_STA|=1<<15;//直接标记接收成功 // TIM4_Set(0); // TIM4_SetARR(99); //重新设置为10ms中断 // } // } // else//非蓝牙扫描模式 // { USART2_RX_STA|=1<<15; //标记接收完成 TIM4_Set(0); //关闭TIM4 // } } } ///USART2 DMA发送配置部分// //DMA1的各通道配置 //这里的传输形式是固定的,这点要根据不同的情况来修改 //从存储器->外设模式/8位数据宽度/存储器增量模式 //DMA_CHx:DMA通道CHx //cpar:外设地址 //cmar:存储器地址 void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输 DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址 DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设 DMA_InitStructure.DMA_BufferSize = 0; //DMA通道的DMA缓存的大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器 } //开启一次DMA传输 void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u16 len) { DMA_Cmd(DMA_CHx, DISABLE ); //关闭 指示的通道 DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小 DMA_Cmd(DMA_CHx, ENABLE); //开启DMA传输 }

 2、向NBIOT发送AT指令并接收应答函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//usmart支持部分 //将收到的AT指令应答数据返回给电脑串口串口1 //mode:0,不清零USART2_RX_STA; // 1,清零USART2_RX_STA; void sim_at_response(u8 mode) { if(USART2_RX_STA&0X8000) //接收到一次数据了 { USART2_RX_BUF[USART2_RX_STA&0X7FFF]=0;//添加结束符 printf("%s",USART2_RX_BUF); //发送到串口 if(mode)USART2_RX_STA=0; } } //NB发送命令后,检测接收到的应答 //str:期待的应答结果 //返回值:0,没有得到期待的应答结果 //其他,期待应答结果的位置(str的位置) u8* NB_check_cmd(u8 *str) { char *strx=0; if(USART2_RX_STA&0X8000) //接收到一次数据了 { USART2_RX_BUF[USART2_RX_STA&0X7FFF]=0;//添加结束符 strx=strstr((const char*)USART2_RX_BUF,(const char*)str); } return (u8*)strx; } //向NB发送命令 //cmd:发送的命令字符串(不需要添加回车了),当cmd<0XFF的时候,发送数字(比如发送0X1A),大于的时候发送字符串. //ack:期待的应答结果,如果为空,则表示不需要等待应答 //waittime:等待时间(单位:10ms) //返回值:1,2,3,发送成功(得到了期待的应答结果) // 0,发送失败 u8 NB_send_cmd(u8 *cmd,u8 *Re1,u8 *Re2,u8 *Re3,u16 waittime) { u8 res=0; USART2_RX_STA=0; if((u32)cmd<=0XFF) { while(DMA1_Channel7->CNDTR!=0); //等待通道7传输完成 USART2->DR=(u32)cmd; }else { u2_printf("%srn",cmd); //发送命令 printf("发送的AT指令是:--> %srn",cmd); //打印调试 } if((Re1&&waittime)||(Re3&&waittime)||(Re2&&waittime)) //需要等待应答 { while(--waittime) //等待倒计时 { delay_ms(12); if(USART2_RX_STA&0X8000)//接收到期待的应答结果 { printf("接收到的应答数据<-- "); printf((const char*)USART2_RX_BUF,"rn"); //收到的模块反馈信息 if (NB_check_cmd(Re1)) { return 1; } if (NB_check_cmd(Re2)) { return 2; } if (NB_check_cmd(Re3)) { return 3; } USART2_RX_STA=0; } } } return res; }

 

接下来就是发送对应的AT指令了

 

最后

以上就是善良百合最近收集整理的关于nbiot+stm32的驱动,使用串口2的全部内容,更多相关nbiot+stm32内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部