不知道是不是因為我的方法不合理,使用了while()循環來485發送幀數據的時候,數碼管會閃爍,普通串口不會,不知道問題是不是在while()這里。
1.png (223.49 KB, 下載次數: 49)
下載附件
2022-3-12 01:34 上傳
//485收發上圖:
貼代碼(stm32f103ret6):
//main.c
#include "stm32f10x.h" // Device header
#include "LED.H"
#include "DISPLAY.H"
#include "TIMER.H"
#include "USART.H"
#include "RS485.H"
int main(void)
{
LED_Init();
DISPLAY1_Init();
KEY_Init();
INTERRUPT_Init();
Timer_Init();
USART1_Init();
RS485_Init();
while (1)
{
}
}
//rs485.h
#ifndef __RS485_H
#define __RS485_H
void RS485_Init(void);
extern unsigned int Uart4_Rx;
extern unsigned char Uart4_Buffer[ ];
extern uint16_t Uart4_Tx_Num;
#endif
//rs485.c
#include "stm32f10x.h" // Device header
#include "DISPLAY.H"
//RS485(UART4) : TX/PC10; RX/PC11; DE/PA12。
void RS485_Init(void)
{
//GPIO_配置UART4_DE(PA12);并初始化為低電平,UART4_485為接收模式。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟對應GPIO_時鐘
GPIO_InitTypeDef GPIO_InitStructure; //定義GPIO_結構體
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_12); //初始化UART4_DE為低電平,UART4_485默認為接收模式。
//GPIO_配置UART4_TX(PC10)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //開啟對應GPIO_時鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//GPIO_配置UART4_RX(PC11)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//USART_配置UART4(波特率9600,長度8字節,1停止位,0奇偶校驗位,0硬件流控制)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); //開啟對應USART_時鐘
USART_InitTypeDef USART_InitStructure; //定義USART_結構體
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_Rx | USART_Mode_Tx; //使能發送與接收功能
USART_Init(UART4, &USART_InitStructure);
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE); //接收中斷,使能
USART_ITConfig(UART4, USART_IT_IDLE, ENABLE); //空閑總線中斷,使能
USART_Cmd(UART4, ENABLE); //使設定的配置生效,但在STM32里,需要配合對應的時鐘使用
//NVIC_配置UART4(優先級分組2,搶占優先級為1,響應優先級為1)
NVIC_InitTypeDef NVIC_InitStructure; //定義NVIC_結構體
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
#define Max_BUFF_Len_4 18
unsigned char Uart4_Buffer[ Max_BUFF_Len_4 ];
unsigned int Uart4_Rx = 0;
void UART4_ReceiveData(void)
{
if(USART_GetITStatus (UART4,USART_IT_RXNE)) //接收中斷
{
Uart4_Buffer[ Uart4_Rx ] = USART_ReceiveData(UART4);
Uart4_Rx ++;
if(Uart4_Rx >=201) //防止達數組上限
{
Uart4_Rx = 0;
}
}
}
uint16_t Uart4_Tx_Num =0;
void UART4_TX(void)
{
static uint32_t Clear;
if(USART_GetITStatus (UART4,USART_IT_IDLE)) //總線空閑中斷
{
while(Uart4_Rx >=1) //485循環發送數組Uart4_Buffer[ ]內的數,解決只一次發送的問題
{
GPIO_SetBits(GPIOA, GPIO_Pin_12); //485發送使能
USART_SendData(UART4,Uart4_Buffer[ Uart4_Tx_Num ]);
Uart4_Tx_Num ++; //485發送順序從數組Uart4_Buffer[ 0-100 ]
while(USART_GetFlagStatus (UART4,USART_FLAG_TC) !=1);
if(Uart4_Tx_Num == Uart4_Rx ) // 待發送完成
{
Uart4_Rx = 0;
Uart4_Tx_Num = 0;
}
}
if(Uart4_Rx ==0)
{
Clear = UART4->SR; //跳出總線空閑中斷
Clear = UART4->DR; //跳出總線空閑中斷
GPIO_ResetBits(GPIOA, GPIO_Pin_12);
}
}
}
void UART4_IRQHandler(void)
{
UART4_ReceiveData();
UART4_TX();
USART_ClearFlag (UART4,USART_FLAG_TC);
}
//usart.h
#ifndef __USART_H
#define __USART_H
void USART1_Init(void);
extern unsigned int Usart1_Rx;
extern unsigned char Usart1_Buffer[ ];
#endif
//usart.c
#include "stm32f10x.h"
//USART1 : TX/PA9; RX/PA10。
void USART1_Init(void)
{
//GPIO_配置USART1_TX(PA9)
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA ,ENABLE ); //GPIOA時鐘開啟
GPIO_InitTypeDef GPIO_InitInstructure;
GPIO_InitInstructure.GPIO_Mode = GPIO_Mode_AF_PP; //選擇引腳模式,TX 需配置為:_AF_PP(復用推挽輸出,用作串口的輸出)
GPIO_InitInstructure.GPIO_Pin = GPIO_Pin_9; //選擇引腳
GPIO_InitInstructure.GPIO_Speed = GPIO_Speed_50MHz; //選擇引腳頻率
GPIO_Init(GPIOA,&GPIO_InitInstructure ); //進行參數初始化
//GPIO_配置USART1_RX(PA10)
GPIO_InitInstructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //選擇引腳模式,RX 需配置為:_IN_FLOATING(浮空輸入,由于其輸入阻抗比較大,一般把這種模式用于標準的通訊協議,比如IIC、USART等)
GPIO_InitInstructure.GPIO_Pin = GPIO_Pin_10; //選擇引腳
GPIO_InitInstructure.GPIO_Speed = GPIO_Speed_50MHz; //RX引腳,也可以不配置引腳頻率
GPIO_Init(GPIOA,&GPIO_InitInstructure ); //進行參數初始化
//USART_配置USART1(波特率9600,長度8字節,1停止位,0奇偶校驗位,0硬件流控制)
RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 ,ENABLE ); //串口USART1時鐘開啟
USART_InitTypeDef USART_InitInstructure;
USART_InitInstructure.USART_BaudRate = 9600; //直接修改波特率即可
USART_InitInstructure.USART_WordLength = USART_WordLength_8b; //長度 8字節
USART_InitInstructure.USART_StopBits = USART_StopBits_1; //1位 停止位
USART_InitInstructure.USART_Parity = USART_Parity_No; //無 奇偶校驗位
USART_InitInstructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無 硬件流控制
USART_InitInstructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //使能發送與接收功能
USART_Init(USART1,&USART_InitInstructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //接收中斷,使能
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //總線空閑中斷,使能
USART_Cmd (USART1 ,ENABLE ); //使設定的配置生效,但在STM32里,需要配合對應的時鐘使用
//NVIC_配置USART1(優先級分組2,搶占優先級為2,響應優先級為2)
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //從stm32f10x.h里第243-268行選擇
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //搶占優先級為2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //響應優先級為2
NVIC_Init(&NVIC_InitStructure); //進行參數初始化
}
#define Max_BUFF_Len_1 18
unsigned char Usart1_Buffer[ Max_BUFF_Len_1 ];
unsigned int Usart1_Rx = 0;
void USART1_IRQHandler(void)
{
if(USART_GetITStatus (USART1,USART_IT_RXNE)) //接收中斷
{
Usart1_Buffer[ Usart1_Rx ] = USART_ReceiveData(USART1);
Usart1_Rx ++;
USART_SendData(USART1,Usart1_Buffer[ Usart1_Rx -1 ]); //接收完立即發
Usart1_Rx = 0;
}
USART_ClearFlag (USART1,USART_FLAG_TC);
}
//TIMER.H
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
void TIM2_IRQHandler(void);
extern uint16_t k;
#endif
//TIMER.c
#include "stm32f10x.h" // Device header
#include "DISPLAY.H"
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //開啟TIM2時鐘
TIM_InternalClockConfig(TIM2); //
//計數器溢出頻率CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)
//內部時鐘默認為72M,此處選用內部時鐘頻率的話
//若設置為72M/(7200-1 +1) /(10000-1 +1) = 1秒,即:1秒進中斷一次。
//結構體(TIM_TimeBaseInitStructure),在本函數內定義一次即可
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //濾波采樣分頻系數,1/2/4分頻。它影響的是濾波器的采樣(輸入)頻率,與輸出無關
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //定時器預分頻器設置,可設置范圍為 0 至 65535,實現 1 至 65536 分頻,內部自動+1。
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //定時器周期,設定自動重載寄存器的值,在事件生成時更新到影子寄存器。可設置范圍為 0 至 65535,內部自動+1。
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //高級定時器才有的。周期倍數:n+1倍。此處為0時,即1倍周期1s;為1時即2倍周期2s,n最大為225(0XFF)。
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //初始化參數(TIM)
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除更新中斷,避免一打開中斷就立刻產生中斷
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //打開定時器更新中斷
//前提條件1:組別優先順序(第0組優先級最強,第4組優先級最弱):NVIC_PriorityGroup_0>NVIC_PriorityGroup_1>NVIC_PriorityGroup_2>NVIC_PriorityGroup_3>NVIC_PriorityGroup_4
//前提條件2:不同組優先級別間,依據優先級強弱,優先級別高的組,其中斷源可以打斷優先級別低的組的正在做的事情;(即:不同組優先級間,可以中斷嵌套)
//前提條件3:組優先級別>搶占優先級別>響應優先級別
//前提條件4:搶占優先級越小,優先級越高;但同組優先級不能相互打斷,也就沒有中斷嵌套
//前提條件5:響應優先級越小的中斷首先執行(不能嵌套),如果響應優先級也均相同,則根據各中斷對應向量表的位置來確定,向量表中越靠前的中斷先響應
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //函數優先級分組配置,共5組(0-4),此處為第1組。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //選擇EXTI2中斷 ,對應之前開啟的TIM2時鐘
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能EXTI2中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應優先級
NVIC_Init(&NVIC_InitStructure); //初始化參數(NVIC)
TIM_Cmd(TIM2, ENABLE); //使能TIM2外設
}
uint16_t k = 1;
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //檢查指定的TIM中斷發生與否
{
k ++;
if(k >= 40)
{
k = 1;
}
Display();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2的中斷待處理位
}
}
//display.h
#ifndef __DISPLAY_H
#define __DISPLAY_H
void DISPLAY1_Init(void);
void Display(void);
extern uint16_t n;
extern uint16_t p;
#endif
//display.c
#include "stm32f10x.h" // Device header
#include "TIMER.H"
#include "USART.H"
#include "RS485.H"
void DISPLAY1_Init(void) //初始化時可以設置為默認完全打開功能,檢測硬件是否OK
{
//PB4:SGE1(位選1);PB3:SEG2(位選2)
//PC13:a;PC14:b;PC15:c;PC1:d;
//PC3:e;PA2:f;PA3:g;PC0:dp。
//GPIO_Write(GPIOC, 0xE00B);
//GPIO_Write(GPIOA,0x000C);
//共陰數碼管:所有陰極(負極)連在(并在)一起。共陽同理。
//結構體:
GPIO_InitTypeDef GPIO_InitStructure; //定義結構體GPIO_InitStructure,用它來傳遞數據
//STM32F10x系列的MCU復位后,PA13/14/15 & PB3/4默認配置為JTAG功能。有時我們為了充分利用MCU I/O口的資源,會把這些端口設置為普通I/O口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //使能相應GPIOB端口時鐘以及AFIO功能時鐘(復用時鐘),在使用時開啟,一方面可以降低功耗;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//枚舉類型:規范、限制變量賦值、取值范圍,使其不能隨意取值。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //選擇引腳模式,結構體GPIO_InitStructure內枚舉類型GPIO_Mode賦值
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4 ; //選擇引腳,結構體GPIO_InitStructure內枚舉類型GPIO_Pin賦值
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //選擇引腳頻率,結構體GPIO_InitStructure內枚舉類型GPIO_Speed賦值
GPIO_Init(GPIOB,&GPIO_InitStructure); //進行參數初始化(GPIOB), &:取地址符號,這里使用地址傳遞
// GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4); //賦值,數碼管高電平有效,非初始化必需步驟
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC ,ENABLE );
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_InitStructure .GPIO_Pin =GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13|GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz ;
GPIO_Init (GPIOC,&GPIO_InitStructure );
// GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3|GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13); //高電平有效
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA,ENABLE );
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_2|GPIO_Pin_3 ;
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
// GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3);
}
uint16_t p;
uint16_t n;
//通過定時器內k(1-40)的自增循環,來進行數碼管的點亮刷新
void Display(void)
{
if(k >= 1 && k <= 19 )
{
GPIO_Write(GPIOB, 0x0010 ); //數碼管位選1
}
if(k >= 20 && k <= 39)
{
GPIO_Write(GPIOB, 0x0008 ); //數碼管位選2
}
//0-9
const uint16_t num_table_1[] = {0xE00A,0xC000,0x600A,0xE002,0xC000,0xA002,0xA00A,0xE000,0xE00A,0xE002}; //,0x0001
const uint16_t num_table_2[] = {0x0004,0x0000,0x0008,0x0008,0x000C,0x000C,0x000C,0x0000,0x000C,0x000C}; //,0x0000
p= 1;//Uart4_Rx / 10 %10 ;
n= 2;//Uart4_Rx % 10;
if(GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_4) == 1)
{
GPIO_Write(GPIOC, num_table_1[p] );
GPIO_Write(GPIOA, num_table_2[p] );
}
if(GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_3) == 1)
{
GPIO_Write(GPIOC, num_table_1[n] );
GPIO_Write(GPIOA, num_table_2[n] );
}
}
|