当前位置:网站首页>Stm32 dossiers d'apprentissage: saisie des applications
Stm32 dossiers d'apprentissage: saisie des applications
2022-07-06 15:23:00 【Bitter tea Seeds】
Table des matières
Un.、Application de la capture d'entrée
1.1、Mesure de la largeur ou de la fréquence des impulsions
1.2、Méthode par étapes pour mesurer la fréquence
1.3、 Méthode de mesure de la largeur des impulsions
2.、 Saisissez le processus de travail de capture
2.1、CH1Par exemple,Saisissez le processus de travail de capture
2.3、 Filtre d'entrée et détection de bord
Trois、Comparaison des résultats
3.1、 Le rôle de la comparaison des résultats
4.1、Capture/Registre des modes de comparaison :TIMx_CCMR1
4.2、Capture/Comparer les registres habilitants:TIMx_CCER
4.3、DMA/Registre d'activation d'interruption:TIMx_DIER
Préface
Introduction de l'utilisation d'un minuteur universel comme saisie d'entrée .Avec TIM5 L'accès à 1(PA0)Pour la capture d'entrée,Capture PA0 Largeur de l'impulsion au niveau supérieur(Avec WK_UP Appuyez sur la touche pour entrer le haut niveau),Imprimer le temps de largeur d'impulsion de haut niveau via le port série.
Un.、Application de la capture d'entrée
La saisie des entrées s'applique généralement de deux façons ,Un aspect est Mesure du temps le long du saut d'impulsion ,D'autre part, PWM Mesure d'entrée.
Le mode de capture d'entrée peut être utilisé pour mesurer la largeur de l'impulsion ou la fréquence.STM32 Le minuteur de,Sauf que TIM6 Et TIM7, D'autres minuteurs ont une fonction de capture d'entrée.
STM32 Saisie des entrées pour, C'est en testant TIMx_CHx Signal de bord sur,Saut du signal de bord(Comme le bord ascendant/Bord de descente)Quand,Valeur du minuteur actuel(TIMx_CNT) Capture stockée dans le canal correspondant/Comparer les registres(TIMx_CCRx)À l'intérieur,Terminer une capture.Vous pouvez également configurer si l'interruption est déclenchée lors de la capture/DMA .
Oui. TIM5_CH1 Pour capter la largeur d'impulsion de haut niveau,C'est - à - dire qu'il faut d'abord définir la capture d'entrée comme détection de bord ascendant,Enregistrer quand le bord ascendant se produit TIM5_CNT Valeur de.Le signal de capture est ensuite configuré pour la capture du bord de descente,Quand le bord de descente arrive,Capture survenue,Et enregistrez ceci TIM5_CNT Valeur.Voilà.,Avant et arrière deux fois TIM5_CNT Différence,Est la largeur de l'impulsion de haut niveau, En même temps TIM5 Nous connaissons la fréquence de comptage,On peut ainsi calculer le temps exact de la largeur de l'impulsion de haut niveau.
1.1、Mesure de la largeur ou de la fréquence des impulsions
1.2、Méthode par étapes pour mesurer la fréquence
Lorsque le canal est capturé TIx Lorsque le bord ascendant apparaît sur,Première capture,Compteur CNT La valeur de est verrouillée dans le registre de capture CCR Moyenne,Et il y a une interruption de capture,Enregistrer une capture dans le programme de service d'interruption(Peut être enregistré avec une variable de drapeau),Et lire la valeur dans le registre de capture à value1 Moyenne.Lorsque le deuxième bord ascendant apparaît,Deuxième capture,Compteur CNT La valeur de est verrouillée à nouveau dans le registre de capture CCR Moyenne,Et entrer à nouveau dans l'interruption de capture,Dans l'interruption de capture,Lire la valeur du registre de capture à value3 Moyenne,Et effacer les drapeaux d'enregistrement de capture.Utilisation value3 Et value1 Nous pouvons calculer la période du signal(Fréquence).
1.3、 Méthode de mesure de la largeur des impulsions
Lorsque le canal est capturé TIx Lorsque le bord ascendant apparaît sur,Première capture,Compteur CNT La valeur de est verrouillée dans le registre de capture CCR Moyenne,Et il y a une interruption de capture,Enregistrer une capture dans le programme de service d'interruption(Peut être enregistré avec une variable de drapeau),Et lire la valeur dans le registre de capture à value1 Moyenne.Puis changez le bord de capture en bord de descente,Le but est de capturer le bord de descente arrière.Quand le bord de descente arrive,Deuxième capture,Compteur CNT La valeur de est verrouillée à nouveau dans le registre de capture CCR Moyenne,Et entrer à nouveau dans l'interruption de capture,Dans l'interruption de capture,Lire la valeur du registre de capture à value3 Moyenne,Et effacer les drapeaux d'enregistrement de capture.Puis réglez le bord de capture à la capture de bord ascendant. La polarité du bord de capture doit être commutée d'avant en arrière lors de la mesure de la largeur de l'impulsion,Si la largeur d'impulsion mesurée est plus longue,Le minuteur déborde,Une interruption de mise à jour se produit en cas de débordement,Nous pouvons enregistrer le débordement à l'intérieur de l'interruption.
2.、 Saisissez le processus de travail de capture
2.1、CH1Par exemple,Saisissez le processus de travail de capture
2.2、Canal d'entrée
Lorsque le signal à mesurer est utilisé à partir de la broche externe du minuteur TIMx_CH1/2/3/4 Entrée,Ça s'appelle TI1/2/3/4, Dans les captures ultérieures, les signaux à mesurer sont tous TIx Pour l'appellation standard .
2.3、 Filtre d'entrée et détection de bord
2.4、Canal de capture
2.5、Pré - diviseur
1、ICx Le signal de sortie passe par un pré - diviseur,Utilisé pour déterminer le nombre d'événements à capturer en même temps.
2、 Spécifique par registre CCMRx Position ICxPSC Configuration, Si vous voulez capturer chaque bord du signal ,Pas de division de fréquence.
Trois、Comparaison des résultats
3.1、 Le rôle de la comparaison des résultats
Quatre、Registre de capture
Les registres nécessaires sont::TIMx_ARR、 TIMx_PSC、TIMx_CCMR1、TIMx_CCER、TIMx_DIER、TIMx_CR1、TIMx_CCR1 .
4.1、Capture/Registre des modes de comparaison :TIMx_CCMR1
Lorsqu'il est utilisé en mode capture d'entrée , Correspond à la description de la deuxième ligne ,Comme le montre la figure,TIMx_CCMR1 C'est clairement pour 2 Configuration des canaux ,8 bits inférieurs[7:0]Pour la capture/Comparer les canaux 1 Contrôle,Et Gao huit Bits[15:8]Pour capturer/Comparer les canaux 2 Contrôle.
Parmi eux CC1S[1:0],Ces deux bits sont utilisés pour CCR1 Configuration du canal pour,Ici, nous mettons en place IC1S[1:0]=01, Ça correspond. Position IC1 Mapping in TI1 Allez.;
Saisie des entrées 1 Pré - diviseur IC1PSC[1:0];Parce que1 Le bord secondaire est déclenché 1 Capture secondaire,Alors choisissez 00 .
Saisie des entrées 1 Filtre IC1F[3:0],Ceci est utilisé pour définir la fréquence d'échantillonnage d'entrée et la longueur du filtre numérique.Parmi eux Est la fréquence d'entrée du minuteur(TIMxCLK),En général 72Mhz.Et Est basé sur TIMx_CR1 De CKD[1:0] Pour déterminer,Si CKD[1:0]Set to 00,Alors .N La valeur est la longueur du filtre,Un exemple simple:Hypothèses IC1F[3:0]=0011,Et la mise en place IC1 Mapping to Channel 1 Allez.,Et déclenché pour le bord ascendant,Donc quand vous capturez le bord ascendant,,Encore une foisFréquence de,Échantillonnage continu à 8 Canal secondaire 1 Niveau,Si tout est haut,Est un déclencheur valide,Déclenche une interruption de capture d'entrée(Si elle est allumée).Cela élimine les impulsions de haut niveau dont la largeur est inférieure à 8 Signaux d'impulsions pour les cycles d'échantillonnage,Pour obtenir l'effet de filtrage.
4.2、Capture/Comparer les registres habilitants:TIMx_CCER
Le plus bas pour utiliser ce registre 2 Bits,CC1E Et CC1P Bits.
Pour activer la capture d'entrée,Vous devez définir CC1E=0,Et CC1P Configurer en fonction de vos besoins.
4.3、DMA/Registre d'activation d'interruption:TIMx_DIER
Une interruption est nécessaire pour traiter les données saisies ,Donc le canal doit être ouvert 1 Dans la comparaison de capture pour Cassé,C'est - à - dire: CC1IE Set to 1.
Cinq、Programmation
5.1、Étapes de configuration
① Le minuteur d'initialisation correspond au canal IOL'horloge de.
② InitialisationIOBouche,Mode comme entrée:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 Entrée
③Initialisation du minuteurARR,PSC
TIM_TimeBaseInit();
④ Initialisation du canal de capture d'entrée
TIM_ICInit();
⑤ Si vous voulez activer l'interruption de capture ,
TIM_ITConfig();
NVIC_Init();
⑥Activer le minuteur:TIM_Cmd();
⑦Écrire une fonction de service d'interruption:TIMx_IRQHandler();
5.2、Programmation
time.cLes codes sont les suivants:
#include "timer.h"
#include "led.h"
#include "usart.h"
/*Initialisation universelle des interruptions de minuterie
Ici, l'horloge est sélectionnée commeAPB1De2X,EtAPB1Pour36M
arr:Valeur de réassemblage automatique.
psc:Fréquence de pré - Division de l'horloge
Le minuteur est utilisé ici3!*/
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //Horloge activée
TIM_TimeBaseStructure.TIM_Period = arr; //Définit la valeur du cycle du registre de recharge automatique pour l'activité de recharge de l'événement de mise à jour suivant Compte à5000Pour500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Le réglage est utilisé commeTIMxValeur de fréquence pré - fractionnée du diviseur de fréquence d'horloge 10KhzFréquence de comptage de
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Définir la Division de l'horloge:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMMode de comptage ascendant
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //SelonTIM_TimeBaseInitStructInitialisation des paramètres spécifiés dansTIMxL'Unit é de base temporelle de
TIM_ITConfig( //Activer ou désactiver la désignationTIMInterruption
TIM3, //TIM2
TIM_IT_Update | //TIM Source d'interruption
TIM_IT_Trigger, //TIM Source d'interruption de déclenchement
ENABLE //Activer
);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3Interruption
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //Priorité0Niveau
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //De la priorité3Niveau
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQCanal activé
NVIC_Init(&NVIC_InitStructure); //SelonNVIC_InitStructParamètres spécifiés dans le périphérique d'initialisationNVICRegistres
TIM_Cmd(TIM3, ENABLE); //ActiverTIMxPériphérique
}
void TIM3_IRQHandler(void) //TIM3Interruption
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //Vérifier la désignationTIMInterruption survenue ou non:TIM Source d'interruption
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //EffacerTIMxBit d'interruption en attente pour:TIM Source d'interruption
LED1=!LED1;
}
}
/*PWMInitialisation de la sortie
arr:Valeur de réassemblage automatique
psc:Fréquence de pré - Division de l'horloge*/
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //ActiverGPIOPériphériques etAFIOL'horloge du module de fonction multiplexage permet
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3Remap partiel TIM3_CH2->PB5 //PourTIM3DeCH2SortiePWMParLEDAfficher
//Définissez Cette broche comme une fonction de sortie multiplex,ProduitsTIM3 CH2DePWMForme d'onde pulsée
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Multiplexage Push - Pull Output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//GPIO_WriteBit(GPIOA, GPIO_Pin_7,Bit_SET); // PA7Tirez
TIM_TimeBaseStructure.TIM_Period = arr; //Définit la valeur du cycle du registre de recharge automatique pour l'activité de recharge de l'événement de mise à jour suivant 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Le réglage est utilisé commeTIMxValeur de fréquence pré - fractionnée du diviseur de fréquence d'horloge Pas de division de fréquence
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Définir la Division de l'horloge:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMMode de comptage ascendant
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //SelonTIM_TimeBaseInitStructInitialisation des paramètres spécifiés dansTIMxL'Unit é de base temporelle de
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Sélectionnez le mode minuteur:TIMMode de modulation de la largeur des impulsions2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Comparer la sortie permet
TIM_OCInitStructure.TIM_Pulse = 0; //Définir la valeur d'impulsion du registre de comparaison de capture à charger
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Polarité de sortie:TIMLa sortie est relativement polaire
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //SelonTIM_OCInitStructParamètres spécifiés dans le périphérique d'initialisationTIMx
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //ActiverTIMxInCCR2Registre préchargé sur
TIM_ARRPreloadConfig(TIM3, ENABLE); //ActiverTIMxInARRRegistre préchargé sur
TIM_Cmd(TIM3, ENABLE); //ActiverTIMxPériphérique
}
//Minuterie5Accès1Configuration de capture d'entrée
TIM_ICInitTypeDef TIM5_ICInitStructure;
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //ActiverTIM5Horloge
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ActiverGPIOAHorloge
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 Paramètres avant purge
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 Entrée
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 Descendez.
//Initialisation du minuteur5 TIM5
TIM_TimeBaseStructure.TIM_Period = arr; //Régler la valeur de réassemblage automatique du compteur
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Pré - diviseur
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Définir la Division de l'horloge:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMMode de comptage ascendant
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //SelonTIM_TimeBaseInitStructInitialisation des paramètres spécifiés dansTIMxL'Unit é de base temporelle de
//InitialisationTIM5Saisissez les paramètres de capture
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 Sélectionner l'entrée IC1Mapping toTI1Allez.
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //Capture de bord ascendant
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Mapping toTI1Allez.
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //Configuration de la Division des entrées,Pas de division de fréquence
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 Configurer le filtre d'entrée Non filtré
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
//Initialisation du Groupe d'interruption
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM3Interruption
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //Priorité2Niveau
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //De la priorité0Niveau
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQCanal activé
NVIC_Init(&NVIC_InitStructure); //SelonNVIC_InitStructParamètres spécifiés dans le périphérique d'initialisationNVICRegistres
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//Autoriser les interruptions de mise à jour ,AllowCC1IECapture interrompue
TIM_Cmd(TIM5,ENABLE ); //Activer le minuteur5
}
u8 TIM5CH1_CAPTURE_STA=0; //Saisissez l'état de capture
u16 TIM5CH1_CAPTURE_VAL; //Saisissez la valeur de capture
//Minuterie5Interruption du programme de service
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//Pas encore capturé avec succès
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)//On a un niveau élevé.
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//Le haut niveau est trop long.
{
TIM5CH1_CAPTURE_STA|=0X80;//L'étiquette a été capturée avec succès une fois
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//Capture1Un événement de capture s'est produit
{
if(TIM5CH1_CAPTURE_STA&0X40) //Capture d'un bord de descente
{
TIM5CH1_CAPTURE_STA|=0X80; //Le marqueur a réussi à capturer un bord ascendant
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 Définir comme capture de bord ascendant
}else //Pas encore commencé,Première prise de bord ascendant
{
TIM5CH1_CAPTURE_STA=0; //Vide.
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //Le marqueur a attrapé le bord ascendant
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 Set to drop Edge capture
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //Effacer le drapeau d'interruption
}
timer.hLa procédure est la suivante::
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
void TIM3_Int_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
void TIM5_Cap_Init(u16 arr,u16 psc);
#endif
main.cLes codes sont les suivants::
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
extern u8 TIM5CH1_CAPTURE_STA; //Saisissez l'état de capture
extern u16 TIM5CH1_CAPTURE_VAL; //Saisissez la valeur de capture
int main(void)
{
u32 temp=0;
delay_init(); //Initialisation de la fonction de retard
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //ParamètresNVICGroupe d'interruption2:2Priorité de préemption des bits,2Priorité de réponse bit
uart_init(115200); //Le port série est initialisé comme115200
LED_Init(); //LEDInitialisation du port
TIM3_PWM_Init(899,0); //Pas de division de fréquence.PWMFréquence=72000/(899+1)=80Khz
TIM5_Cap_Init(0XFFFF,72-1); //Par1MhzNombre de fréquences pour
while(1)
{
delay_ms(10);
TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);
if(TIM_GetCapture2(TIM3)==300)TIM_SetCompare2(TIM3,0);
if(TIM5CH1_CAPTURE_STA&0X80)//Un bord ascendant a été capturé avec succès
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp*=65536;//Temps de débordement total
temp+=TIM5CH1_CAPTURE_VAL;//Obtenir le temps total de haut niveau
printf("HIGH:%d us\r\n",temp);//Imprimer le temps total de nivellement des points élevés
TIM5CH1_CAPTURE_STA=0;//Activer la prochaine capture
}
}
}
边栏推荐
- Global and Chinese market of goat milk powder 2022-2028: Research Report on technology, participants, trends, market size and share
- csapp shell lab
- Crawling cat's eye movie review, data visualization analysis source code operation instructions
- Servlet
- Stc-b learning board buzzer plays music
- How to rename multiple folders and add unified new content to folder names
- LeetCode#53. Maximum subarray sum
- 安全测试入门介绍
- How to build a nail robot that can automatically reply
- Mysql database (III) advanced data query statement
猜你喜欢
CSAPP家庭作业答案7 8 9章
ucore Lab 1 系统软件启动过程
Take you to use wxpy to create your own chat robot (plus wechat interface basic data visualization)
Do you know the performance testing terms to be asked in the software testing interview?
FSM和i2c实验报告
Crawling cat's eye movie review, data visualization analysis source code operation instructions
软件测试工作太忙没时间学习怎么办?
Brief introduction to libevent
Video scrolling subtitle addition, easy to make with this technique
UCORE lab8 file system experiment report
随机推荐
How to rename multiple folders and add unified new content to folder names
Leetcode notes - dynamic planning -day7
ucore lab 2
Investment should be calm
LeetCode#36. Effective Sudoku
软件测试方法有哪些?带你看点不一样的东西
ucore lab5用户进程管理 实验报告
ucore lab6 调度器 实验报告
Mysql database (I)
全网最详细的postman接口测试教程,一篇文章满足你
ucore lab7
自动化测试你必须要弄懂的问题,精品总结
Global and Chinese markets of PIM analyzers 2022-2028: Research Report on technology, participants, trends, market size and share
MySQL数据库(二)DML数据操作语句和基本的DQL语句
CSAPP Shell Lab 实验报告
The most detailed postman interface test tutorial in the whole network. An article meets your needs
Global and Chinese market of maleic acid modified rosin esters 2022-2028: Research Report on technology, participants, trends, market size and share
Emqtt distribution cluster and node bridge construction
In Oracle, start with connect by prior recursive query is used to query multi-level subordinate employees.
MySQL数据库(四)事务和函数